Swift中的通用完成处理程序

wan*_*der 2 generics closures swift

我有一个方法,有一个名为的方法performRequest().它需要一个JSONRequest参数.JSONRequest看起来像这样:

public typealias JSONCompletionHandler = ([Entity]?, NSError?) -> Void

public class JSONRequest: Request {
    public var completionHandler: JSONCompletionHandler
    public var endPoint: String
}
Run Code Online (Sandbox Code Playgroud)

而且performRequest()看起来是这样的:

public func performJSONRequest<T where T: Entity>(jsonRequest: JSONRequest, _: Type) {
        // Make a request which returns a data object
        var entities = self.convertJSONData(data, jsonKey: jsonRequest.jsonKey, T.self)
        // Error: 'T' is not identical to 'Entity'
        jsonRequest.completionHandler(entities, error)
}
Run Code Online (Sandbox Code Playgroud)

如您所见,它调用convertJSONData()如下所示:

func convertJSONData<T where T: Entity>(jsonData: AnyObject, _: T.Type) -> [T] {
        // Convert the data into Swift collection classes, enumerate over them, and create model objects
        var json = JSON(data: jsonData as NSData, options: nil, error: nil)
        var entities = [T]()

        for obj in json {
            let book = T(json: obj)
            entities.append(book)
        }

    return entities
Run Code Online (Sandbox Code Playgroud)

实体是一个协议,我的所有模型类,例如AuthorBook,符合.

它定义了一种方法:init(json: JSON).既然T定义为T:Entity,我可以调用T:(json: obj)创建符合的任何类的实例Entity.

我希望能够用于performJSONRequest()执行符合实体的任何对象的请求.例如,我想构建一个像这样的Book实例的请求:

var request = JSONRequest(endPoint: "books") { (let object: [Entity]?, let error: NSError?) -> Void in
    // Cast object to [Book] and have fun
}

performJSONRequest<Book>(request)
Run Code Online (Sandbox Code Playgroud)

我不能为我的生活找到我将如何实现这一点.现在,我在performJSONRequest()方法中说错了'T' is not identical to 'Entity'.如果我在完成处理程序中定义数组,因为[AnyObject]我得到相同的错误:'T' is not identical to 'AnyObject'.

谢谢你的帮助!

Nat*_*ook 14

解决方案是将泛型类型移动到JSONRequest类中 - 这种方式JSONCompletionHandler可以使用您请求的泛型类型而不仅仅是Entity协议来定义.(你的一些代码似乎有点伪 - 所以这可能需要一些调整才能适应你的实现.)

JSONRequest现在是一个具有Entity类型约束的泛型类:

public class JSONRequest<T: Entity>: Request {
    // completion handler defined in terms of `T`
    public typealias JSONCompletionHandler = ([T]?, NSError?) -> Void

    // no further changes        
    public var completionHandler: JSONCompletionHandler
    public var endPoint: String
    public init(endPoint: String, completionHandler: JSONCompletionHandler) {
        self.endPoint = endPoint
        self.completionHandler = completionHandler
    }
}
Run Code Online (Sandbox Code Playgroud)

performJSONRequest不再需要作为单独参数传递的类型.由于jsonRequest是专门的,它从该参数获取类型信息:

public func performJSONRequest<T: Entity>(jsonRequest: JSONRequest<T>) {
    // create array of `T` somehow 
    var entities: [T] = []
    var error: NSError?

    // completionHandler expects [T]? and NSError?
    jsonRequest.completionHandler(entities, error)
}
Run Code Online (Sandbox Code Playgroud)

在创建JSONRequest实例时,完成处理程序中给出的类型(例如[Book]?)将设置泛型的类型JSONRequest,并在整个过程中保持:

var request = JSONRequest(endPoint: "books") { (books: [Book]?, error) in
    println(books?.count)
}
performJSONRequest(request)
Run Code Online (Sandbox Code Playgroud)