複数のユーザー アカウントを持つことができるアプリがあります。それらすべてをバックグラウンドで更新する必要があります。問題は:
- 時間は限られています (最大 30 秒ですが、リクエストにはそれ以上かかる場合があります)
- すべてのリクエストは非同期です
いつ完了ハンドラを呼び出す必要がありますか?
複数のユーザー アカウントを持つことができるアプリがあります。それらすべてをバックグラウンドで更新する必要があります。問題は:
いつ完了ハンドラを呼び出す必要がありますか?
グランド セントラル ディスパッチのグループは、基本的にこの問題を解決するために作られました。件名に関するAppleのドキュメントから:
ディスパッチ グループは、一連のブロック オブジェクトの完了を監視する方法です。グループは、他のタスクの完了に依存するコードに便利な同期メカニズムを提供します。グループの使用の詳細については、キューに入れられたタスクのグループを待機するを参照してください。
グループを使用してタスクのグループを監視するには、2 つの方法があります。1 つ目は非同期コールバックを使用する方法で、もう 1 つはグループ化されたすべてのタスクが完了するまで現在のキューをブロックする方法です。設定はどちらでも同じです。
手始めに簡単な例を紹介します (Swift で回答しますが、Objective-C でも同じアプローチが 1-1 に適用されます)。まず、グループを定義します。
let group = dispatch_group_create()
完了したい各非同期タスクごとに 1 回、グループに入ります。
dispatch_group_enter(group)
dispatch_group_enter(group)
非同期タスクを実行し、各タスクを完了としてマークする場合は、次を呼び出しますdispatch_group_leave
。
firstAsyncTask {
dispatch_group_leave(group)
}
secondAsyncTask {
dispatch_group_leave(group)
}
前述のように、グループ内のすべてのタスクが完了すると、現在のキュー (スレッドをブロックする) で待機するか、ブロックを指定して非同期的に呼び出すことができます。
dispatch_group_wait(group, 30 * NSEC_PER_SEC)
これにより、すべてのグループ タスクが完了するか、30 秒が経過するまで (どちらか早い方)、現在のスレッドでの実行が停止します。
時間制限を解除したい場合:
dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
これは、それほど多くはないという理由だけで、少し単純です。ブロックを呼び出すブロックを 2 番目の引数として指定します。グループのタスクがすべて完了すると、このブロックが呼び出されます。
dispatch_group_notify(group, dispatch_get_main_queue()) {
// Code goes here.
}
私は最近、同様の状況に直面し、ここに質問を投稿しました。
秘訣は、すべてのリクエストを (非同期で) 開始し、それらのそれぞれにコールバック関数を実行させて、それが最後のリクエストであったかどうか、またはまだ保留中のリクエストがあるかどうかを確認することです。
それが本当に最後のリクエストだった場合、コールバックは最終的な完了ハンドラを実行する必要があります。
ソースコードは、この質問に対する私の回答からプレイグラウンドに直接コピーできます。