Swift中的通用完成处理程序
我有一个方法,它有一个名为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
实体是一个协议所有我的模型类,例如Author
和Book
,符合。其定义了一种方法: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'
。
感谢您的帮助!
解决方案是将通用类型向上移动到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)
这太棒了。我没有意识到在'JSONRequest'中定义'JSONCompletionHandler'将允许它使用它的'T'类型占位符。非常感谢你的完整答案! – wander 2014-12-07 10:45:28