Type does not conform to protocol

11,263

viewForValue is supposed to return a class which inherits from UIView and implements SomeProtocol. You have defined 2 classes having no direct relationship - they just inherit from UIView and implement SomeProtocol.

When the function has to determine the return type, the direct concrete type both classes inherit from is UIView, so that is what viewForValue returns.

In order to fix the problem, you have to create a direct and concrete relationship between the 2 classes, by creating a 3rd class inheriting from UIView and implementing SomeProtocol:

protocol SomeProtocol {
    func setValue(value: Int)
}

class SomeClass: UIView, SomeProtocol {
    func setValue(value: Int) {

    }
}

class SomeSubclass : SomeClass {
}

class SomeOtherSubclass : SomeClass {
}

func viewForValue<T where T: SomeProtocol, T: SomeClass>(param: Int) -> T {
    var someView: T
    if param > 0 {
        someView = SomeSubclass() as T
    } else {
        someView = SomeOtherSubclass() as T
    }
    someView.setValue(2)
    someView.frame = CGRectZero
    return someView
}

viewForValue(2)

Addendum: reading the OP comment below, the purpose is to dynamically instantiate existing UIKit classes inheriting from UIView. So the proposed solution doesn't apply.

I think that extending UIView by implementing SomeProtocol should work:

protocol SomeProtocol {
    func setValue(value: Int)
}

extension UIView : SomeProtocol {
    func setValue(value: Int) {
    }
}

func viewForValue<T where T: SomeProtocol, T: UIView>(param: Int) -> UIView {
    var someView: T
    if param > 0 {
        someView = UILabel() as T
    } else {
        someView = UIImageView() as T
    }
    someView.setValue(2)
    someView.frame = CGRectZero
    return someView
}

but it looks like there's a compiler bug. This code in a playground shows a message stating that:

Communication with the playground service was interrupted unexpectedly. The playground service "com.apple.dt.Xcode.Playground" may have generated a crash log.

whereas in an iOS application compilation fails due to a segmentation fault 11.

Share:
11,263
Kamchatka
Author by

Kamchatka

Updated on June 21, 2022

Comments

  • Kamchatka
    Kamchatka almost 2 years

    I'm still having trouble understanding some subtleties of generics in Swift. I define the following types:

    protocol SomeProtocol {
        func setValue(value: Int)
    }
    
    class ProtocolLabel : UILabel, SomeProtocol {
        func setValue(value: Int) {
    
        }
    }
    
    class ProtocolImageView : UIImageView, SomeProtocol {
        func setValue(value: Int) {
        }
    }
    

    viewForValue(2) Now I defined the following function. I expect T to be a UIView that conforms to protocol SomeProtocol.

    func viewForValue<T where T: SomeProtocol, T: UIView>(param: Int) -> UIView {
        var someView: T
        if param > 0 {
            someView = ProtocolLabel() as T
        } else {
            someView = ProtocolImageView() as T
        }
        someView.setValue(2)
        someView.frame = CGRectZero
        return someView
    }
    

    However, I'm getting the following compile error when I execute the code:

    viewForValue(2) // <-- Type 'UIView' does not conform to protocol 'SomeProtocol'
    

    It seems that in the where clause I can't specify a class that does not implement the protocol. Why is that?

    Thanks in advance.