Swift 3 における非同期処理
Published at 2016-10-22
自作の 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 を指定する。
userInteractive: The user-interactive quality of service class.userInitiated: The user-initiated quality of service class.default: The default quality of service class.utility: The utility quality of service class.background: The background quality of service classunspecified: The absence of a quality of service class.
取得したキューには sync や async 、 asyncAfter といった関数が生えているので、同期で処理するのか非同期で処理するのかによって決める。
これによって AsyncDispatcher でやりたかった「より Swift らしいコード」は達成されてしまったので、こちらを使うようにした。