Reputation: 2056
I want to have a view function that returns the first UIResponder matching a given type:
extension UIView {
func responder<T, Result: UIResponder & T>(ofType: T) -> Result? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder?.next
if let matchingResponder = parentResponder as? Result {
return matchingResponder
}
}
return nil
}
}
Unfortunately the compiler show the following error:
Non-protocol, non-class type 'T' cannot be used within a protocol-constrained type
My question is simple: how do I tell the compiler T is a protocol type?
Upvotes: 0
Views: 354
Reputation: 32793
You don't need two arguments, one should suffice. Also you can provide a default value for the type
parameter, in case the compiler can infer the result:
extension UIView {
func findResponder<T>(ofType type: T.Type = T.self) -> T? {
func find(_ current: UIResponder) -> T? {
if let result = current as? T { return result }
guard let next = current.next else { return nil }
return find(next)
}
return find(self)
}
}
Note that you can't restrict T
to be a protocol only, since in Swift protocols are not first class types. However you should not need this.
I also reorganised the method implementation to a more functional style.
Usage:
let dataSource = view.findResponder(ofType: UITableViewDataSource.self)
let navCtrl: UINavigationController = view.findResponder()
Upvotes: 2