Help us understand the problem. What is going on with this article?

Swiftで複数の非同期処理を並列実行させて、すべてが終わったらコールバックを受け取る関数

More than 3 years have passed since last update.

改良したものをライブラリとして公開しました。
Swiftで複数の非同期処理を扱うライブラリAsyncKitを書きました


非同期処理を並列に実行させてすべてが終わったら別の処理を行う、ということをしたいとき、GCDのgroupを使う方法があります。
ただ、毎回GCDのコードを書くのは美しくないですし、やり方を忘れてしまいがちです。

そこで新しく parallel という関数を作りました。
JavaScriptの非同期処理を扱うライブラリ "async" にあるparallel関数を参考にしています。

Quick Example

parallel(
    [
        { done in done("1") },
        { done in done("2") }
    ]) { results in
        print(results) // -> [Optional(1), Optional(2)]
}

詳しい使い方

非同期処理を行う AsyncProcess 型のクロージャを用意。

let process1: AsyncProcess = { done in

    request() { // なんらかの非同期処理
        // ...

        // 非同期処理が終わったら `done()` を呼ぶ
        // `done()` には非同期処理の結果を渡す
        done("1")
    }
}

// 並列処理を行いたい分だけクロージャを用意。
let process2: AsyncProcess = { done in
    request() {
        done("2")
    }
}

parallel関数にクロージャの配列を渡す。

parallel([process1, process2]) { results in
    // すべての非同期処理が終わったらこのクロージャが実行される

    // `results` 配列には非同期処理の結果が、parallel関数に渡した非同期処理の順番と同じ順番で入っている
    print(results) // -> [Optional(1), Optional(2)]
}

コード

typealias AsyncProcess = (done: AnyObject? -> ()) -> ()

func parallel(acyncProcesses: [AsyncProcess], completion: [AnyObject?] -> ()) {
    var results = [AnyObject?](count: acyncProcesses.count, repeatedValue: nil)

    let group = dispatch_group_create()
    for (i, acyncProcess) in acyncProcesses.enumerate() {
        dispatch_group_enter(group)
        acyncProcess { result in
            results[i] = result
            dispatch_group_leave(group)
        }
    }

    dispatch_group_notify(group, dispatch_get_main_queue()) {
        completion(results)
    }
}

できないこと

  • 結果の型を指定できない
    • typealiasでの定義をGenericにできなかったので
    • 工夫すればできなくはなさそうですが (Generic typealias in Swift) 、コードのシンプルさを優先しました
  • 丁寧なエラーハンドリングができない
    • 非同期処理中でエラーが発生した場合 done(nil) として、 resultsnil が入っているかチェックすればとりあえずエラーハンドリングできます
    • または、NSError型を渡しても同様にできます
    • 理想的には、非同期処理がすべて成功した場合、1つでも失敗した場合で分岐を別けるのが丁寧かと思います

環境

Apple Swift version 2.1 (swiftlang-700.1.101.6 clang-700.1.76)
Target: x86_64-apple-darwin14.5.0

参考

GCDのgroupについて
http://commandshift.co.uk/blog/2014/03/19/using-dispatch-groups-to-wait-for-multiple-web-services/

JSのasyncライブラリ
https://github.com/caolan/async

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away