Swift Generics 参数 T 限定为 Class 的一点记录

今天看以前写的网络请求的方法如下:

static func listItemWithRefIndex(refIndex: Int, orientation: String, direction: Int,  
  nitems: Int, response: (items: [Item]) -> Void) {
    var param = [String: AnyObject]()
    param["ref_index"] = refIndex
    param["orientation"] = orientation
    param["direction"] = direction
    param["nitems"] = items
    Alamofire.request(Router.ReadList(param)).responseCollection { 
      (_, _, result: Result<[Item]>) -> Void in
        if let value = result.value {
            response(items: value)
        }
    }
}

越看越不爽,如果下次增加方法,请求类型变成了 Student:

static func listItemWithRefIndex(refIndex: Int, orientation: String,  
    direction: Int, nitems: Int, response: (items: [Student]) -> Void) {
        var param = [String: AnyObject]()
        // 参数拼接略
        // ....
        Alamofire.request(Router.ReadList(param)).respon seCollection { 
          (_, _, result: Result<[Student]>) -> Void in
            if let value = result.value {
                response(items: value)
            }
        }
    }

后面那段关于 Alamofire 的代码重复写了很多次。然后就想再抽一个方法,这个方法的参数有:

  1. 遵循 URLRequestConvertible 协议的类型,如上面的 Router
  2. response 里面Closures中参数的类型,如上面的 Item 和 Student
  3. 最后就是 response 了

问题在于 response 的 Closures中的参数,怎么声明。

  1. 首先它要是个 Class,问题转变为要遵循 AnyObject 协议,因为所有 class 都隐式现实了这个协议
  2. 然后他要遵循 ResponseCollectionSerializable 协议
    最后在 way 的提醒下,写成这样:
static func sendRequestWithRouter<T: protocol<AnyObject, ResponseCollectionSerializable>>(router: Router,  
    classType: T.Type, completionHandler: (items: [T]) -> ()) {  
        Alamofire.request(router).responseCollection { 
          (_, _, result: Result<[T]>) -> Void in
            if let value = result.value {
                completionHandler(items: value)
            }
        }
    }

<T: protocol<AnyObject, ResponseCollectionSerializable>

  1. AnyObject 声明了 T 是一个 Class,为什么要是 Class,要调用 T.Type
  2. T: ResponseCollectionSerializable,声明了 T 要遵循ResponseCollectionSerializable 协议

classTpye: T.Type 中的 T.Type 表示存储 T 这个类型的本身,而 T.self 表示取出其类型,这样就达到我的目的了,最后变成这样:

static func listItemWithRefIndex(refIndex: Int, orientation: String,  
    direction: Int, nitems: Int, response: (items: [Item]) -> Void) {
        var param = [String: AnyObject]()
        param["ref_index"] = refIndex
        param["orientation"] = orientation
        param["direction"] = direction
        param["nitems"] = nitems
        sendRequestWithRouter(Router.ReadList(param), classType: Item.self, completionHandler: response)
}

yuanpt

Read more posts by this author.

Subscribe to Talk is cheap, Show me the world!

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!