To naprawdę dobre pytanie. Twoje podejście jest całkowicie słuszne. Jednak Alamofire może faktycznie pomóc Ci to jeszcze bardziej usprawnić.
Twój przykładowy podział kolejki wysyłki kodu
W swoim przykładowym kodzie przeskakujesz między następującymi kolejkami wysyłania:
- Kolejka wysyłkowa NSURLSession
- Kolejka wysyłkowa TaskDelegate do weryfikacji i przetwarzania serializatora
- Główna kolejka wysyłkowa do wywoływania programu obsługi zakończenia
- Kolejka o wysokim priorytecie do obsługi formatu JSON
- Główna kolejka wysyłkowa do aktualizacji interfejsu użytkownika (w razie potrzeby)
Jak widać, skaczesz wszędzie. Przyjrzyjmy się alternatywnemu podejściu wykorzystującemu potężną funkcję wewnątrz Alamofire.
Kolejki wysyłek odpowiedzi Alamofire
Alamofire ma optymalne podejście wbudowane we własne przetwarzanie niskiego poziomu. Pojedyncza response
metoda, która ostatecznie jest wywoływana przez wszystkie niestandardowe serializatory odpowiedzi, obsługuje niestandardową kolejkę wysyłania, jeśli zdecydujesz się jej użyć.
Chociaż GCD świetnie radzi sobie z przeskakiwaniem między kolejkami wysyłkowymi, chcesz uniknąć przeskakiwania do zajętej kolejki (np. Głównego wątku). Eliminując skok z powrotem do głównego wątku w środku przetwarzania asynchronicznego, możesz potencjalnie znacznie przyspieszyć działanie. Poniższy przykład ilustruje, jak to zrobić, używając logiki Alamofire od razu po wyjęciu z pudełka.
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
println("Parsing JSON on thread: \(NSThread.currentThread()) is main thread: \(NSThread.isMainThread())")
println(JSON)
dispatch_async(dispatch_get_main_queue()) {
println("Am I back on the main thread: \(NSThread.isMainThread())")
}
}
)
Alamofire 3.x (Swift 2.2 i 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
print("Parsing JSON on thread: \(NSThread.currentThread()) is main thread: \(NSThread.isMainThread())")
print(response.result.value)
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
print("Parsing JSON on thread: \(Thread.current) is main thread: \(Thread.isMainThread)")
print(response.result.value)
DispatchQueue.main.async {
print("Am I back on the main thread: \(Thread.isMainThread)")
}
}
)
Podział kolejki wysyłki Alamofire
Oto zestawienie różnych kolejek wysyłek związanych z tym podejściem.
- Kolejka wysyłkowa NSURLSession
- Kolejka wysyłkowa TaskDelegate do weryfikacji i przetwarzania serializatora
- Niestandardowa współbieżna kolejka wysyłkowa menedżera do obsługi formatu JSON
- Główna kolejka wysyłkowa do aktualizacji interfejsu użytkownika (w razie potrzeby)
Podsumowanie
Eliminując pierwszy przeskok z powrotem do głównej kolejki wysyłania, wyeliminowałeś potencjalne wąskie gardło, a także sprawiłeś, że całe żądanie i przetwarzanie są asynchroniczne. Niesamowite!
Powiedziawszy to, nie mogę wystarczająco podkreślić, jak ważne jest poznanie wewnętrznych zasad tego, jak naprawdę działa Alamofire. Nigdy nie wiadomo, kiedy możesz znaleźć coś, co naprawdę pomoże Ci ulepszyć własny kod.
response
metody jest teraz wywoływanyresponseSerializer
zamiastserializer
(w Alamofire 3.0). To spowodowałoCannot call value of non-function type 'NSHTTPURLResponse?'
błąd, który trochę mnie zdezorientował.Mała aktualizacja dla Swift 3.0, Alamofire (4.0.1), Edycja dla @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 } })
źródło
Uzupełniając idealną odpowiedź od @cnoon, jeśli lubisz mnie
ResponseObjectSerializable
, możesz osadzić to współbieżne zachowanie w samym rozszerzeniu żądania: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) } } } }
źródło