#1. やりたいこと
API通信で非同期処理を実装する際に、複数の通信(ループ処理)がある場合に、最後までループ処理が完了した後にその結果を取り出す。
#2. 実装方法
DispatchGroup()
を使用した実装方法を示す。ここで、クロージャ_hoge_、_fuga_は通信処理である。
以下のスニペットで、DispatchGroup()
がない状態を想定すると、「Sequence #4」は hoge 、 fuga のコールバック取得よりも先に実行される可能性が高いため、Sequence #1 → 4 → 5 → 2 → 3
の順になる。
DispatchGroup()
を使用することで、Sequence #1 → 4 → 2 → 3 → 5
の順になる。
ポイントは、dispatchGroup.enter()
とdispatchGroup.leave()
が2回あること。
最初のenter()
でカウンターが+1され、 hoge 処理が実行開始される。「Sequence #1」の通信が完了する頃には「Sequence #2」の通信を開始しているため、処理は「Sequence #2」の通信の結果を待たずに「Sequence #4」に移行するが、この時「Sequence #2」の位置のenter()
によってカウンターが上がっているため、「Sequence #3」のコールバック完了まで「Sequence #5」に移行しない。
なお、同様の機能を果たす実装方法は他にも考えられるが、検討した限りはこれが良いと思った。また、実際にはエラーに対する条件分岐などが入り込むが、この考え方を使用できる。
let dispatchGroup = DispatchGroup()
let dispatchqueue = DispatchQueue.global(qos: .userInitiated)
dispatchGroup.enter()
dispatchqueue.async {
hoge { foos in
// Sequence #1
for foo in foos {
dispatchGroup.enter()
// Sequence #2
fuga { bars in
dispatchGroup.leave()
// Sequence #3
}
}
// Sequence #4
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: dispatchqueue){
// Sequence #5
}
#3. 参考リンク
Swiftで複数の非同期処理の完了時に処理を行う
DispatchQueueを使って容量のあるファイルをダウンロードする方法