Contents 非表示
Swift Concurrencyとは
AppleがSwift 5.5(iOS 15〜)で導入した新しい非同期処理モデル。
従来のcompletionHandler
やDispatchQueue
をもっと安全・直感的に書けるのが最大のポイント。
Swift Concurrencyの何が嬉しいのか
- 可読性 → ネスト地獄から解放
- 安全性 → データ競合を防ぐ仕組み(actor)
- スケーラビリティ → async let / TaskGroupで並列処理がサクッと書ける
非同期の概念を復習
- 同期処理(Sync)
ポケモントレーナーが 1匹ずつ順番に技を出す
ピカチュウが10万ボルトを出し終わるまで、リザードンは待機。
= 「終わるまで次に進めない」。 - 非同期処理(Async)
ピカチュウが電気技を撃ちながら、リザードンは同時に「かえんほうしゃ」を発動できる。
= 複数の処理が独立して進む。
つまり:
同期 = シングルバトル(一匹ずつ)
非同期 = ダブルバトル(同時進行)
実装
CompletionHandlerからの脱却
昔のコード
fetchUser { user, error in
guard let user else { return }
fetchPosts(userId: user.id) { posts, error in
guard let posts else { return }
fetchComments(postId: posts[0].id) { comments, error in
// ネスト地獄になりやすい
}
}
}
async / await バージョン
func fetchUser() async throws -> User { ... }
let user = try await fetchUser()
try / try? / do-catch の使い分け
let user = try await fetchUser() // 上位に投げる (自分ではエラー処理せず、呼び出し元(上の関数)に任せる)
let user = try? await fetchUser() // nil で握りつぶす
do {
let user = try await fetchUser()
} catch {
print(error)
}
Task {}の使い方
Swiftの非同期関数 (async)は、非同期コンテキストからしか呼べない。
= 通常の同期コード直下でawaitは使えない
❌ NGパターン
struct ContentView: View {
var body: some View {
Button("Fetch User") {
// エラー: 'async' call in a function that does not support concurrency
let user = try await fetchUser()
print(user.name)
}
}
}
⭕️ パターン (実際にView層で直接書くことはないですがわかりやすさ重視)
struct ContentView: View {
var body: some View {
Button("Fetch User") {
Task {
do {
let user = try await fetchUser()
print("User name: \(user.name)")
} catch {
print("Error: \(error)")
}
}
}
}
}
ポイント:
Button
のアクションは 同期クロージャ → 直接await
は禁止Task {}
を作ると「非同期コンテキスト」が用意される- その中で
await
やtry
が使えるようになる
まとめ
最初はとっつきにくいかもしれないが、慣れるとCompletionHandlerでネストマシマシになるより綺麗に書けるようになるのかもしれない?
書きながら覚える、これが一番。
↓ 次回
