Reputation:
I would like to create a protocol for view on watchOS, iOS and TvOS, so I can get their subviews and superviews in a generic way.
At first I tried this :
protocol ViewProtocol: Hashable {
var superview: Self? { get }
var subviews: [Self] { get }
}
And then I extend the UIView
class like this :
extension UIView: ViewProtocol {}
But I get this error from the compiler:
<unknown>:0: error: protocol 'ViewProtocol' requirement 'superview' cannot be satisfied by a non-final class ('UIView') because it uses 'Self' in a non-parameter, non-result type position
I'm not sur to understand the problem (I think it's related to the compiler not being able to use Self in a non final class), so I tried the following :
The protocol would look like this :
protocol ViewProtocol: Hashable {
func getSuperview() -> ViewProtocol?
func getSubviews() -> [ViewProtocol]
}
But now I get this error at the protocol declaration :
Protocol 'ViewProtocol' can only be used as a generic constraint because it has Self or associated type requirements
So I tried this :
protocol ViewProtocol: Hashable {
func getSuperview<T: ViewProtocol>() -> T?
func getSubviews<T: ViewProtocol>() -> [T]
}
And the implementation look like this:
extension UIView: ViewProtocol {
func getSuperview<T>() -> T? where T : ViewProtocol {
return self.superview as! T?
}
func getSubviews<T>() -> [T] where T : ViewProtocol {
return self.subviews as! [T]
}
}
But now when I try to use the method on generic type ViewProtocol
I get this error : Generic parameter 'T' could not be inferred
Can someone help me ? I would like to fundamentally understand what's going on here and why it is so difficult to make that work ?
Upvotes: 1
Views: 1283
Reputation: 63272
You can't have a Self
requirement in non-final classes, and here's an example to illustrate why that wouldn't make sense:
protocol Copyable {
var copyOfSelf: Self { get }
}
final class Car {
let name: String
init(name: String) { self.name = name }
}
extension Car: Copyable {
var copyOfSelf: Car { return Car(name: self.name) }
}
class SportsCar: Car {
// Inherited:
// var copyOfSelf: Car { return Car(name: self.name) }
// Notice that it still returns `Car`, not `SportsCar`,
// Breaking the conformance to `Copyable`
}
Upvotes: 1