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.
The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol.
Protocols as TypesProtocol is a type. You can use it in many places like: As a parameter type or return type in a function, method, or initializer. As the type of a constant, variable, or property.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With