1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

冗長になりがちなDispatchGroupを簡潔に使用する方法

Last updated at Posted at 2020-11-16

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が始まります。

閲覧ありがとうございました。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?