Type does not match protocol

It’s still hard for me to understand some of the intricacies 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 have defined the following function. I expect T to be a UIView that conforms to SomeProtocol protocol .

 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, when I execute the code, I get the following compilation error:

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

It seems that in the where clause I cannot specify a class that does not implement the protocol. Why is this?

Thanks in advance.

+6
source share
1 answer

viewForValue should return a class that inherits from UIView and implements SomeProtocol . You have defined 2 classes that are not directly related - they simply inherit from UIView and implement SomeProtocol .

When a function needs to determine the return type, the direct concrete type inherited from both classes is UIView , so viewForValue returned.

To fix this problem, you need to create a direct and specific relationship between the two classes by creating a 3rd class that inherits from UIView and implements 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 goal is to dynamically create existing UIKit classes that inherit from UIView . Therefore, the proposed solution does not apply.

I think that extending the 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 is a compiler error. This code on the playground shows a message that:

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

while the compilation of the iOS application fails due to segmentation error 11.

+4
source

Source: https://habr.com/ru/post/975291/


All Articles