2014-12-06 45 views
2

我有一個方法,它有一個名爲performRequest()的方法。它需要一個JSONRequest參數。 JSONRequest看起來是這樣的:Swift中的通用完成處理程序

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

public class JSONRequest: Request { 
    public var completionHandler: JSONCompletionHandler 
    public var endPoint: String 
} 

而且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) 
} 

正如你可以看到,它調用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 

實體是一個協議所有我的模型類,例如AuthorBook,符合。其定義了一種方法:init(json: JSON)。由於T定義爲T:Entity,因此我可以致電T:(json: obj)創建任何符合Entity的類的實例。

我希望能夠使用performJSONRequest()執行請求的任何對象符合實體。例如,我要建立喜歡這本書實例的請求:

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

performJSONRequest<Book>(request) 

我不能爲我的生命找出我將如何實現這一點。現在,我在performJSONRequest()方法中出現錯誤'T' is not identical to 'Entity'。如果我在完成處理程序中將數組定義爲[AnyObject],則會得到相同的錯誤:'T' is not identical to 'AnyObject'

感謝您的幫助!

回答

8

解決方案是將通用類型向上移動到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 
    } 
} 

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

在創建JSONRequest例如,在完成處理程序給出的類型(例如,[Book]?)將設置類型爲通用JSONRequest,並持有整個過程:

var request = JSONRequest(endPoint: "books") { (books: [Book]?, error) in 
    println(books?.count) 
} 
performJSONRequest(request) 
+0

這太棒了。我沒有意識到在'JSONRequest'中定義'JSONCompletionHandler'將允許它使用它的'T'類型佔位符。非常感謝你的完整答案! – wander 2014-12-07 10:45:28