swiftのasync/awaitを使った非同期処理の実装
今回のテーマはswiftのasync/awaitになります。
この記事は アイソルート Advent Calendar 2023 3日目の記事です。
こんにちは。モバイルソリューショングループのfujinami.mです。
今回のテーマはswiftのasync/awaitで非同期実装する方法です。
今までは非同期処理をクロージャで実装していて、非同期処理が重なったりするとネストが深くなっていってコードの可読性が下がっていました。使ってみてコードの可読性も上がったので、その実装方法になります。
目次
クロージャを使用した実装例
今まで非同期処理はクロージャを使用して実装していました。
ただ、クロージャを使用した非同期処理はコールバックで処理を行うため、複数の非同期処理を実装する際に「コールバック地獄」を発生させてしまいます。
以下はその一例になります。
// 最初の非同期処理 firstAsyncTask { firstResult in switch firstResult { case .success(let firstData): // 2番目の非同期処理 secondAsyncTask(input: firstData) { secondResult in switch secondResult { case .success(let secondData): print("response: \(secondData)") case .failure(let error): print("error: \(error)") } } case .failure(let error): print("error: \(error)") } }
ちょっと読みづらいですね…
今回は例として2つの非同期処理としましたが、これが3つになったり並行で非同期処理をしようとすると更に読みづらくなってしまいます。
async/awaitを使用した実装例
次はasync/awaitを使用した実装になります。
// 非同期処理 func fetchAsyncTasks() async { do { let firstResult = try await firstAsyncTask() let secondResult = try await secondAsyncTask(input: firstResult) print("response: \(secondResult)") } catch { print("error: \(error)") } } // 非同期処理を実行 Task { await fetchAsyncTasks() }
クロージャを使用したときの実装と比べて、async/awaitを使うと2つの非同期処理の可読性が非常に高くなりました。
注意点
UIKitでの実装: DispatchQueue.main.asyncを使用してUIを更新
UIKitの場合、Taskを使用して非同期処理を実行しても必ずメインスレッドに戻れるわけでないため、非同期処理が完了した後にUIを更新する必要がある場合、DispatchQueue.main.asyncを明示的に使用してメインスレッドに戻る必要があります。
// 非同期処理 func fetchAsyncTasks() async -> String { do { let firstResult = try await firstAsyncTask() let secondResult = try await secondAsyncTask(input: firstResult) return "response: \(secondResult)" } catch { return "error: \(error)" } } // 非同期処理を実行 Task { let result = await fetchAsyncTasks() DispatchQueue.main.async { // UIを更新 self.label.text = "\(result)" } }
まとめ
以上、クロージャとasync/awaitの実装差分と非同期処理の実装でした。
個人的にはasync/awaitを使用することで、改修のしやすさとコードの可読性が向上すると感じました。