简体   繁体   中英

Define a generic type as protocol type in function definition

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?

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM