用于JSON请求的AlamoFireasynchronouscompletionHandler
在使用了AlamoFire框架之后,我注意到了completionHandler在主线程上运行。 我想知道是否下面的代码是一个很好的做法,在完成处理程序中创build一个核心数据导入任务:
Alamofire.request(.GET, "http://myWebSite.com", parameters: parameters) .responseJSON(options: .MutableContainers) { (_, _, JSON, error) -> Void in dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { () -> Void in if let err = error{ println("Error:\(error)") return; } if let jsonArray = JSON as? [NSArray]{ let importer = CDImporter(incomingArray: jsonArray entity: "Artist", map: artistEntityMap); } }); }
这是一个非常好的问题。 你的方法是完全有效的。 不过,Alamofire实际上可以帮助你更精简这一点。
您的示例代码调度队列细分
在你的示例代码中,你在以下调度队列之间跳转:
- NSURLSession调度队列
- TaskDelegate派遣队列进行validation和序列化处理
- 主调度队列调用你的完成处理程序
- JSON处理的高优先级队列
- 主调度队列更新用户界面(如有必要)
正如你所看到的,你到处跳来跳去。 让我们来看看利用Alamofire内部强大function的另一种方法。
Alamofire响应调度队列
Alamofire在自己的低级处理中有一个最佳的方法。 最终被所有自定义响应序列化器调用的单一response
方法,如果您select使用它,则支持自定义调度队列。
虽然GCD在派遣队列之间跳跃时非常棒,但是您希望避免跳转到繁忙的队列(例如主线程)。 通过消除在asynchronous处理过程中跳回到主线程,可以大大加快速度。 下面的例子演示了如何使用Alamofire逻辑直接开箱即用。
Alamofire 1.x
let queue = dispatch_queue_create("com.cnoon.manager-response-queue", DISPATCH_QUEUE_CONCURRENT) let request = Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"]) request.response( queue: queue, serializer: Request.JSONResponseSerializer(options: .AllowFragments), completionHandler: { _, _, JSON, _ in // You are now running on the concurrent `queue` you created earlier. println("Parsing JSON on thread: \(NSThread.currentThread()) is main thread: \(NSThread.isMainThread())") // Validate your JSON response and convert into model objects if necessary println(JSON) // To update anything on the main thread, just jump back on like so. dispatch_async(dispatch_get_main_queue()) { println("Am I back on the main thread: \(NSThread.isMainThread())") } } )
Alamofire 3.x(Swift 2.2和2.3)
let queue = dispatch_queue_create("com.cnoon.manager-response-queue", DISPATCH_QUEUE_CONCURRENT) let request = Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"]) request.response( queue: queue, responseSerializer: Request.JSONResponseSerializer(options: .AllowFragments), completionHandler: { response in // You are now running on the concurrent `queue` you created earlier. print("Parsing JSON on thread: \(NSThread.currentThread()) is main thread: \(NSThread.isMainThread())") // Validate your JSON response and convert into model objects if necessary print(response.result.value) // To update anything on the main thread, just jump back on like so. dispatch_async(dispatch_get_main_queue()) { print("Am I back on the main thread: \(NSThread.isMainThread())") } } )
Alamofire 4.x(Swift 3)
let queue = DispatchQueue(label: "com.cnoon.response-queue", qos: .utility, attributes: [.concurrent]) Alamofire.request("http://httpbin.org/get", parameters: ["foo": "bar"]) .response( queue: queue, responseSerializer: DataRequest.jsonResponseSerializer(), completionHandler: { response in // You are now running on the concurrent `queue` you created earlier. print("Parsing JSON on thread: \(Thread.current) is main thread: \(Thread.isMainThread)") // Validate your JSON response and convert into model objects if necessary print(response.result.value) // To update anything on the main thread, just jump back on like so. DispatchQueue.main.async { print("Am I back on the main thread: \(Thread.isMainThread)") } } )
Alamofire调度队列细分
以下是涉及这种方法的不同调度队列的细目。
- NSURLSession调度队列
- TaskDelegate派遣队列进行validation和序列化处理
- 用于JSON处理的自定义pipe理器并发调度队列
- 主调度队列更新用户界面(如有必要)
概要
通过消除第一跳回到主调度队列,您已经消除了潜在的瓶颈,并且您已经完成了整个请求和asynchronous处理。 真棒!
就这样说,我不能强调熟悉Alamofire的内部工作是多么的重要。 你永远不知道什么时候可以find能够帮助你改进自己的代码的东西。
Swift 3.0,Alamofire的小更新(4.0.1),编辑@cnoon回答:
let queue = DispatchQueue(label: "com.cnoon.manager-response-queue", qos: .userInitiated, attributes:.concurrent) Alamofire?.request(SERVER_URL, method: .post, parameters: ["foo": "bar"], encoding: JSONEncoding.default,//by default headers: ["Content-Type":"application/json; charset=UTF-8"]) .validate(statusCode: 200..<300).//by default responseJSON(queue: queue, options: .allowFragments, completionHandler: { (response:DataResponse<Any>) in switch(response.result) { case .success(_): break case .failure(_): print(response.result.error) if response.result.error?._code == NSURLErrorTimedOut{ //TODO: Show Alert view on netwok connection. } break } })
只需补充来自@cnoon的完美答案,如果您喜欢我使用ResponseObjectSerializable
,则可以将此并发行为embedded到请求扩展本身中:
extension Request { public func responseObject<T: ResponseObjectSerializable>(completionHandler: Response<T, NSError> -> Void) -> Self { let responseSerializer = ResponseSerializer<T, NSError> { request, response, data, error in guard error == nil else { return .Failure(error!) } let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments) let result = JSONResponseSerializer.serializeResponse(request, response, data, error) switch result { case .Success(let value): if let response = response, responseObject = T(response: response, representation: value) { return .Success(responseObject) } else { let failureReason = "JSON could not be serialized into response object: \(value)" let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason) return .Failure(error) } case .Failure(let error): return .Failure(error) } } let queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT) return response(queue: queue, responseSerializer: responseSerializer) { response in dispatch_async(dispatch_get_main_queue()) { completionHandler(response) } } } }