swift_concurrency について
非同期コードの作成や Swift 6 への移行に取り組む開発者向けの Swift 並行処理ガイドです。async/await、構造化並行処理、アクター分離、厳格なチェックを扱い、移行手順と実践的な指針を示します。
主な機能
- 01async/await と Task の解説
- 02構造化並行処理とタスクグループ
- 03アクター、分離、Sendable の説明
- 04Swift 6 の厳格な並行性チェック
- 05移行手順とよくあるエラーへの対処
活用シーン
- 01完了ハンドラーを async/await に移行
- 02複数の非同期処理を並行実行
- 03共有状態を保護しデータ競合に対処
- 04プロジェクトを Swift 6 に移行
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ swiftzilla/ skills --skill swift_concurrencyインストール後、Claude Code で/swift_concurrencyを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/swift6_strict_mode.mdasync_await.mdsendable.mdisolation.md詳細
Swift Concurrency
このスキルでは、Swift 5.5 から Swift 6 までの最新の並行処理機能を扱います。async/await、構造化並行処理、アクター、Swift 6 の厳格なデータ競合安全性などが含まれます。
概要
Swift の最新の並行処理モデルを使うと、非同期コードをより安全かつ直感的に記述できます。Swift 6 ではさらに、コンパイル時のデータ競合安全性が導入され、潜在的な並行処理のバグがコンパイラーエラーになります。
参照できる資料
Swift 6 と厳格な並行処理
- Swift 6 Strict Mode - 完全な並行処理チェック、データ競合の防止
- Sendable Protocol - Sendable 準拠、@Sendable クロージャー、スレッド安全性
- Isolation & Actors - @MainActor、グローバルアクター、リージョンベースの隔離
並行処理の基礎
- Async/Await - 非同期関数、Task、TaskGroup、アクターの基礎
Swift 6 の主な機能
デフォルトでの厳格な並行処理
Swift 6 では、コンパイル時にデータ競合の安全性が強制されます。
// ❌ Compile-time error in Swift 6
var globalCounter = 0
func increment() {
globalCounter += 1 // Error: concurrent access
}
// ✅ Safe with actor isolation
actor Counter {
private var value = 0
func increment() { value += 1 }
}
Sendable プロトコル
並行処理の境界を越えて安全に共有できる型としてマークします。
struct User: Sendable {
let id: Int
let name: String
}
@Sendable func process() async {
// Captures must be Sendable
}
MainActor とグローバルアクター
@MainActor
class ViewModel: ObservableObject {
@Published var items = [Item]()
}
@globalActor
actor DatabaseActor {
static let shared = DatabaseActor()
private init() {}
}
クイックリファレンス
Async/Await の基礎
func fetchData() async throws -> Data {
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
Swift 6 への移行チェックリスト
- Swift 6 言語モードを有効にする
- 厳格な並行処理チェックを有効にする
- グローバルな可変状態をアクターでラップする
- 型に Sendable 準拠を追加する
- @Sendable クロージャー内の Sendable でないキャプチャーを修正する
- @MainActor で UI コードを隔離する
- サードパーティの依存関係を監査する
非同期コードの実行
// Fire-and-forget
Task {
let result = await asyncOperation()
}
// With priority
Task(priority: .background) {
await heavyComputation()
}
// With cancellation
let task = Task {
try await longRunningOperation()
}
task.cancel()
並行処理
// Async let (parallel await)
async let task1 = fetchUser()
async let task2 = fetchSettings()
let (user, settings) = try await (task1, task2)
// TaskGroup
try await withThrowingTaskGroup(of: Item.self) { group in
for id in ids {
group.addTask { try await fetchItem(id: id) }
}
return try await group.reduce(into: []) { $0.append($1) }
}
アクターによるスレッド安全性
actor BankAccount {
private var balance: Double = 0
func deposit(_ amount: Double) {
balance += amount
}
func getBalance() -> Double {
return balance
}
}
let account = BankAccount()
await account.deposit(100)
隔離の境界
// Crossing isolation boundaries
@MainActor
func updateUI() async {
// On main thread
let data = await fetchData() // Switch to non-isolated
label.text = data // Back to main thread
}
// Region transfer
func process() async {
let data = Data() // Disconnected
await save(data) // Transfer to actor
// ❌ Can't use data here anymore
}
Swift 6 と Swift 5.x の比較
| 機能 | Swift 5.x | Swift 6 |
|---|---|---|
| 並行処理チェック | 警告 | エラー |
| データ競合の安全性 | 実行時 | コンパイル時 |
| Sendable の強制 | オプトイン | 必須 |
| グローバル変数の安全性 | 警告 | エラー |
| 厳格モード | 実験的 | デフォルト |
ベストプラクティス
Swift 6 のベストプラクティス
- 早い段階で Swift 6 モードを有効にする - 今すぐ移行を始めます
- 共有状態にはアクターを使う - ロックよりもアクターを優先します
- Sendable な型を設計する - 最初から型を Sendable にします
- @MainActor で UI を隔離する - すべての UI コードをメインスレッドで実行します
- 隔離リージョンを守る - 転送後に値を使わないでください
- コンパイル時の安全性を活用する - データ競合の検出はコンパイラーに任せます
- ドメインアクターを作成する - 負荷の高い処理にはカスタムのグローバルアクターを使います
並行処理全般
- async/await を優先する - 完了ハンドラーよりも優先します
- 構造化並行処理を使う - 明確なタスク階層を保ちます
- キャンセルを処理する - Task.isCancelled を確認します
- 値型を使う - 不変データはスレッドセーフです
- 共有された可変状態を避ける - またはアクターで保護します
完了ハンドラーからの移行
// Before (Swift 5)
func fetchUser(completion: @escaping (Result<User, Error>) -> Void) {
URLSession.shared.dataTask(with: url) { data, response, error in
// Handle result
completion(result)
}.resume()
}
// After (Swift 6)
func fetchUser() async throws -> User {
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
Swift 6 のよくあるエラー
| エラー | すぐにできる修正 |
|---|---|
| グローバルへの並行アクセス | アクターでラップする |
| @Sendable 内で Sendable でない値を使用 | 型を Sendable にする |
| アクター隔離への違反 | await を追加するか、隔離を変更する |
| 転送後の使用 | 転送前に使うか、値をコピーする |
| Main actor の隔離 | @MainActor アノテーションを追加する |
リソース
- Swift Evolution: https://github.com/apple/swift-evolution
- SE-0412: グローバル変数の厳格な並行処理
- SE-0471: SerialExecutor の隔離チェック
- SE-0430: パラメーターの送信
- SE-0414: リージョンベースの隔離
- Apple Docs: https://developer.apple.com/documentation/swift/concurrency
- SwiftZilla: https://swiftzilla.dev
詳細情報
各参照ファイルには、特定のトピックに関する詳細な情報、コード例、ベストプラクティスが記載されています。Swift の並行処理について詳しくは、https://swiftzilla.dev をご覧ください。
コメント
Markdown 対応