Ayant utilisé le framework AlamoFire, j'ai remarqué que le completionHandler est exécuté sur le thread principal. Je me demande si le code ci-dessous est une bonne pratique pour créer une tâche d'importation Core Data dans le gestionnaire d'achèvement:
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);
}
});
}
C'est une très bonne question. Votre approche est parfaitement valide. Cependant, Alamofire peut réellement vous aider à rationaliser encore plus.
Dans votre exemple de code, vous passez d'une file d'attente à une autre:
Comme vous pouvez le voir, vous sautez partout. Jetons un coup d'œil à une approche alternative exploitant une fonctionnalité puissante d'Alamofire.
Alamofire a une approche optimale intégrée à son propre traitement de bas niveau. La méthode unique response
qui est finalement appelée par tous les sérialiseurs de réponses personnalisées prend en charge une file d’attribution personnalisée si vous choisissez de l’utiliser.
Bien que GCD permette de passer d’une file d’attente de répartition à une autre, vous voulez éviter de passer à une file d’attente occupée (par exemple, le thread principal). En éliminant le retour au thread principal au milieu du traitement async, vous pouvez potentiellement accélérer considérablement les choses. L'exemple suivant montre comment faire cela en utilisant la logique Alamofire directement et immédiatement.
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())")
}
}
)
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())")
}
}
)
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)")
}
}
)
Voici la répartition des différentes files d’attribution impliquées dans cette approche.
En éliminant le premier saut dans la file d'attente de répartition principale, vous avez éliminé tout goulot d'étranglement potentiel et rendu l'ensemble de votre demande et de votre traitement asynchrones. Impressionnant!
Cela dit, je ne saurais trop insister sur l’importance de se familiariser avec le fonctionnement interne d’Alamofire. Vous ne savez jamais quand vous pouvez trouver quelque chose qui peut vraiment vous aider à améliorer votre propre code.
Petite mise à jour pour Swift 3.0, Alamofire (4.0.1), Edit for @cnoon answer:
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
}
})
Pour compléter simplement la réponse parfaite de @cnoon, si vous aimez bien utiliser ResponseObjectSerializable
, vous pouvez intégrer ce comportement simultané à l'extension de requête elle-même:
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)
}
}
}
}