[解決済み] AlamoFireのJSONリクエスト用非同期completionHandler
質問
AlamoFireフレームワークを使用していて、completionHandlerがメインスレッドで実行されることに気づきました。以下のコードは、補完ハンドラ内でCore Dataインポートタスクを作成するための良い練習になるのかどうか疑問に思っています。
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ディスパッチキュー
- 完了ハンドラを呼び出すためのメインディスパッチキュー
- JSON処理用の高優先度キュー
- ユーザーインターフェイスを更新するためのメインディスパッチキュー(必要であれば)
見ての通り、あちこち飛び回っていますね。Alamofireの強力な機能を利用した別のアプローチを見てみましょう。
Alamofireのレスポンスディスパッチキュー
Alamofireは、低レベルの処理に最適な手法を組み込んでいます。単一の
response
メソッドは、最終的にすべてのカスタム応答シリアライザーによって呼び出され、あなたがそれを使用することを選択した場合、カスタムディスパッチキューをサポートしています。
GCD はディスパッチキュー間のホッピングで素晴らしいですが、ビジー状態のキュー (例えばメインスレッド) にジャンプするのは避けたいものです。非同期処理の途中でメインスレッドに戻るジャンプをなくすことで、潜在的に物事をかなり高速化することができます。次の例では、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ディスパッチキュー
- JSON処理用のカスタムマネージャの並列ディスパッチキュー
- ユーザーインターフェイスを更新するためのメインディスパッチキュー(必要な場合)
概要
メインのディスパッチキューに戻る最初のホップをなくすことで、潜在的なボトルネックをなくすと同時に、リクエストと処理全体を非同期にすることができました。素晴らしい!
とはいえ、Alamofireが実際にどのように動作するかの内部構造に精通することがいかに重要であるかは、いくら強調してもしきれません。いつ自分のコードを改善するのに役立つ何かを見つけることができるかわかりません。
関連
-
swift 4.0でのdispatch_async,dispatch_afterの使用について
-
[解決済み] Swiftで1つのビューコントローラの向きを縦向きのみに固定する方法
-
[解決済み] UIViewの定高制約をプログラムで更新するには?
-
[解決済み] Swift 1.2では、宣言は「final」と「dynamic」の両方にはなり得ないというエラーがある
-
[解決済み] Swiftで複数のカスタムセルを持つUITableview
-
[解決済み] 非'@objc'メソッドは'@objc'プロトコルのオプション要件を満たしていない
-
[解決済み] プロパティの型が内部型を使用しているため、publicを宣言することができない
-
[解決済み] Swiftでenumをプロトコルに準拠させるには?
-
[解決済み] NSUserdefaultsの配列の保存と読み込みはどのように行うのですか?
-
[解決済み] Swift 3 GCD API変更後のdispatch_once
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
swift 4.0でのdispatch_async,dispatch_afterの使用について
-
[解決済み] 非'@objc'メソッドは'@objc'プロトコルのオプション要件を満たしていない
-
[解決済み] Swift - 複数条件でオブジェクトの配列を並べ替える
-
[解決済み] Swift で型に表示されるテキスト表現を変更するにはどうしたらいいですか?
-
[解決済み] カスタムイニシャライザを持つSwift enumはrawValueイニシャライザを失う
-
[解決済み] Swiftの関数パラメータとしてのプロトコルに準拠したクラス
-
[解決済み] NSLog(@"%s", __PRETTY_FUNCTION__) の Swift 代替はあるか?
-
[解決済み] NSUserdefaultsの配列の保存と読み込みはどのように行うのですか?
-
[解決済み] Swiftのthrowとrethrowsの違いは何ですか?
-
[解決済み] iOS 9のスワイプ可能なテーブルビューセル