EagleLand

2016.10.22

Swift 3における非同期処理

自作の iOS クライアントのコードを Swift 3 に移行した。その時に非同期処理について色々調べたのでメモ。

GCD (Grand Central Dispatch)

macOS や iOS といった Apple のプラットフォームにおいて非同期で処理したい場合は GCD (Grand Central Dispatch) という仕組みを使う。

UI に関する更新はメインスレッドで行う必要があるので dispatch_get_main_queue() で取得するメインキューに処理を追加し、通信などの非同期でも差し支えない処理はグローバルディスパッチキューという並列処理用のキューを dispatch_get_global_queue() で参照する。それぞれのキューに処理を追加するには同期か非同期かを、 dispatch_sync()dispatch_async() で指定できる。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
    // グローバルキューで実行される

    dispatch_async(dispatch_get_main_queue(), {
        // メインキューで実行される
    });
});

dispatch_sync() で処理を追加すると同期的に実行されるので、追加した処理が終わるまで次の処理に進まない。逆に dispatch_async() で追加された場合、追加された処理の実行完了を待たずに次の処理に進む。

Swift の GCD についてはSwift GCD入門という記事により詳しく書かれている。

DispatchQueueクラスが追加された

これをiOS+Swiftの非同期処理のヘルパークラスのような形でラップしていたが、 Swift 3 からは DispatchQueue というクラスが追加されている。これを使うと非同期処理は次のように書ける。

DispatchQueue.global().async {
    // グローバルキューで実行される

    DispatchQueue.main.async {
        // メインキューで実行される
    }
}

メインキューを取得する dispatch_get_main_queue()DispatchQueue.main に対応し、グローバルキューを取得する dispatch_get_global_queue()DispatchQueue.global() に対応する。グローバルキューの取得時の優先度指定は DispatchQueue.global() に引数を渡せるようになっており、 enum の DispatchQoS.QoSClass を指定する。

取得したキューには syncasyncasyncAfter といった関数が生えているので、同期で処理するのか非同期で処理するのかによって決める。

これによって AsyncDispatcher でやりたかった「より Swift らしいコード」は達成されてしまったので、こちらを使うようにした。