Qiita初投稿。
Zhalenといいます。読み方は「ツァーレン」です。本名ではありません。
「さっさと結果だけ教えろ」という方は、下記のMethod
をコピペしてUsage
のように使って下さい。
#Traditional
DispatchGroupとは、複数の非同期処理を管理できるものです。
これを用いると、複数の非同期処理全てが終了したときに何かを実行するということができます。
その従来の使い方は、こんな感じです。
let dispatchGroup: DispatchGroup = DispatchGroup()
let dispatchQueue: DispatchQueue = DispatchQueue(label: "queue")
dispatchGroup.enter()
dispatchQueue.async(group: dispatchGroup) {
//処理1
dispatchGroup.leave()//処理1が終わったことを知らせる。
}
dispatchGroup.enter()
dispatchQueue.async(group: dispatchGroup) {
//処理2
dispatchGroup.leave()//処理2が終わったことを知らせる。
}
disptchGroup.notify(queue: dispatchQueue) {
//全ての処理が終了した時にここを実行
}
SNSアプリなどを開発してAPI通信関連のゴタゴタをやっていると、どうしてもこれを何回も何回も書かなくてはいけなくなります。そのため、簡潔に書きたくなります。
理想は、こうです。
DispatchGroup([処理1, 処理2]) {
//全ての処理が終わった時の処理
}
このように書くことができれば、分かりやすく、そして簡潔です。
以下のメソッドはそれを実現します。
#Method
//DispatchGroupAsync
func DispatchGroupAsync(label: String, attributes: DispatchQueue.Attributes?, handles: [(((() -> Void)?) -> Void)?], completion: (() -> Void)?) {
let dispatchGroup: DispatchGroup = DispatchGroup()
let dispatchQueue: DispatchQueue = (attributes == nil) ? DispatchQueue(label: label) : DispatchQueue(label: label, attributes: attributes!)
handles.forEach { (handle) in
dispatchGroup.enter()
dispatchQueue.async(group: dispatchGroup) {
handle? {
dispatchGroup.leave()
}
}
}
dispatchGroup.notify(queue: dispatchQueue) {
DispatchQueue.main.async {
completion?()
}
}
}
ラベルとアトリビュートを付与する結果とはなりましたが、致し方ありません。そして、スレッドのズレを補正するため、一応最後でメインスレッドに戻しています。これは本質的ではありませんが実際、mainThreadで行わなければならない処理が多くそれらをいちいちDispatchQueue.main.asyncと書くのが面倒だったのでこうしました。
#Usage
DispatchGroupAsync(
label: "queue",
attributes: nil,
handles: [モンスターボール当てる(_:), カチって音が鳴る(_:)],
completion: {
print("ポケモンゲットだぜ!")
}
)
func モンスターボール当てる(_ completion: (() -> Void)?) {
//dispatchGroup.leave() を置いていたところに completion?() を置く。
}
func カチって音が鳴る(_ completion: (() -> Void)?) {
//dispatchGroup.leave() を置いていたところに completion?() を置く。
}
ちなみに、attributes
を.concurrent
にすると並列となり、処理1と処理2を同時に処理し始めます。上記のようにnil
だと直列となり、処理1が終わった後に処理2が始まります。
閲覧ありがとうございました。