AgentSkillsCN

swift6-strict-concurrency

当用户提出“迁移到 Swift 6”“启用严格并发”“修复 Sendable 错误”“添加 @MainActor”“解决数据竞争警告”“实现 Actor 隔离”“配置完整的并发检查”“修复 Swift 6 警告”“使类具备 Sendable 属性”“处理 @Sendable 闭包”“迁移至 Swift 6”“启用严格并发”“修复 Sendable 错误”“添加 @MainActor”“解决数据竞争警告”“实现 Actor 隔离”“配置完整的并发检查”“修复 Swift 6 警告”“使类具备 Sendable 属性”“处理 @Sendable 闭包”时,或当用户需要有关 Swift 6 严格并发迁移、Sendable 协议的实现、Actor 隔离模式、数据竞争安全性,以及从 Swift 5 迁移至 Swift 6 的各类策略的指导时,应使用此技能。

SKILL.md
--- frontmatter
name: swift6-strict-concurrency
description: |
  This skill should be used when the user asks to "migrate to Swift 6",
  "enable strict concurrency", "fix Sendable errors", "add @MainActor",
  "resolve data race warnings", "implement actor isolation",
  "configure complete concurrency checking", "fix Swift 6 warnings",
  "make class Sendable", "handle @Sendable closures",
  "Swift 6 に移行", "Strict Concurrency を有効化", "Sendable エラーを修正",
  "@MainActor を追加", "データ競合警告を解決", "アクター分離を実装",
  "完全な並行性チェックを設定", "Swift 6 警告を修正",
  "クラスを Sendable にする", "@Sendable クロージャを扱う",
  or needs guidance on Swift 6 strict concurrency migration,
  Sendable protocol implementation, actor isolation patterns,
  data race safety, and migration strategies from Swift 5 to Swift 6.
version: 1.0.0

Swift 6 Strict Concurrency

Swift 6 の Strict Concurrency モードへの移行・対応を支援するスキル。Sendable プロトコル、Actor 分離、データ競合の安全性などを網羅的にカバーする。

Overview

Target Platform: iOS 17+ / macOS 14+ / Swift 6.0+

主要な変更点:

  • Complete concurrency checking がデフォルトで有効
  • すべての型がデータ競合に対して安全であることを保証
  • Sendable プロトコルによる型安全な境界定義
  • Actor isolation による排他的アクセス制御

Core Concepts:

  • Sendable Protocol
  • Actor Isolation (@MainActor, custom actors)
  • @Sendable Closures
  • Data Race Safety

Quick Start Checklist

Swift 6 Strict Concurrency を有効化する手順:

  1. Xcode Build Settings で設定

    code
    SWIFT_STRICT_CONCURRENCY = complete
    
  2. または Package.swift で設定

    swift
    .target(
        name: "MyTarget",
        swiftSettings: [
            .swiftLanguageMode(.v6)
        ]
    )
    
  3. 段階的に有効化(推奨)

    • minimaltargetedcomplete の順で警告を解消
  4. 主要なエラーを修正

    • 非 Sendable 型のキャプチャ
    • Actor 境界を越えるデータアクセス
    • @MainActor の不足

Xcode Project Configuration

Build Settings

設定説明
SWIFT_STRICT_CONCURRENCYminimal最小限の警告(デフォルト)
SWIFT_STRICT_CONCURRENCYtargeted@Sendable を明示した部分のみ
SWIFT_STRICT_CONCURRENCYcomplete完全なデータ競合チェック

Package.swift

swift
// Swift 6 言語モード
let package = Package(
    name: "MyPackage",
    platforms: [.iOS(.v17), .macOS(.v14)],
    targets: [
        .target(
            name: "MyTarget",
            swiftSettings: [
                .swiftLanguageMode(.v6)
            ]
        )
    ]
)

// Swift 5.x で段階的に有効化
.target(
    name: "MyTarget",
    swiftSettings: [
        .enableUpcomingFeature("StrictConcurrency")
    ]
)

詳細は references/xcode-configuration.md を参照。

Sendable Protocol

自動準拠する型

以下の型は自動的に Sendable に準拠:

  • 値型(struct/enum): すべてのプロパティが Sendable の場合
  • Actor: 常に Sendable
  • 基本型: Int, String, Bool, etc.
swift
// 自動的に Sendable
struct UserData: Sendable {
    let id: UUID
    let name: String
}

enum Status: Sendable {
    case pending
    case completed(Date)
}

手動準拠(Reference Types)

swift
// final class + immutable properties
final class Config: Sendable {
    let apiKey: String
    let timeout: TimeInterval

    init(apiKey: String, timeout: TimeInterval) {
        self.apiKey = apiKey
        self.timeout = timeout
    }
}

@unchecked Sendable

内部で同期処理を行う場合に使用(慎重に):

swift
final class ThreadSafeCache: @unchecked Sendable {
    private let lock = NSLock()
    private var storage: [String: Data] = [:]

    func get(_ key: String) -> Data? {
        lock.lock()
        defer { lock.unlock() }
        return storage[key]
    }

    func set(_ key: String, value: Data) {
        lock.lock()
        defer { lock.unlock() }
        storage[key] = value
    }
}

詳細は references/sendable-guide.md を参照。

Actor Isolation

@MainActor

UI 更新を行うクラスに適用:

swift
@Observable
@MainActor
class ViewModel {
    var items: [Item] = []
    var isLoading = false
    var errorMessage: String?

    func loadData() async {
        isLoading = true
        defer { isLoading = false }

        do {
            items = try await api.fetchItems()
        } catch {
            errorMessage = error.localizedDescription
        }
    }
}

Custom Actor

データの排他的アクセスが必要な場合:

swift
actor ImageCache {
    private var cache: [URL: UIImage] = [:]

    func image(for url: URL) -> UIImage? {
        cache[url]
    }

    func setImage(_ image: UIImage, for url: URL) {
        cache[url] = image
    }

    func clear() {
        cache.removeAll()
    }
}

// 使用例
let cache = ImageCache()
let image = await cache.image(for: url)

nonisolated

Actor 内で同期アクセスを許可:

swift
actor DataManager {
    let id: String  // let は nonisolated でアクセス可能

    nonisolated var identifier: String {
        id  // await 不要
    }

    // Hashable 準拠
    nonisolated func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
}

詳細は references/actor-isolation.md を参照。

@Sendable Closures

基本的な使用法

swift
// Task は @Sendable クロージャを要求
Task {
    // このクロージャ内でキャプチャする値は Sendable でなければならない
    await performWork()
}

// 明示的な @Sendable
func performAsync(_ work: @Sendable @escaping () async -> Void) {
    Task { await work() }
}

キャプチャリストの注意点

swift
@MainActor
class ViewModel {
    var count = 0

    func increment() {
        // BAD: self は非 Sendable
        Task.detached {
            self.count += 1  // エラー
        }

        // GOOD: @MainActor に戻る
        Task {
            self.count += 1  // OK(MainActor を継承)
        }
    }
}

詳細は examples/sendable-closures.swift を参照。

Common Errors and Fixes

エラーメッセージ原因解決策
Capture of 'x' with non-sendable type in @Sendable closure非 Sendable 型をクロージャでキャプチャSendable に準拠させるか actor を使用
Call to main actor-isolated method in synchronous nonisolated context@MainActor メソッドを非分離コンテキストから呼び出しawait を追加、または呼び出し元も @MainActor に
Stored property 'x' of 'Sendable'-conforming class must be immutableSendable クラスに var プロパティlet に変更、または actor を使用
Actor-isolated property 'x' cannot be mutated from a non-isolated contextアクター外からプロパティを変更await を使用してアクターメソッド経由で変更
Non-sendable type 'X' cannot cross actor boundary非 Sendable 型をアクター境界で渡すSendable に準拠させる
Task-isolated value of type 'X' passed as a strongly transferred parameterTask 間でのデータ転送Sendable に準拠させるか、コピーを渡す

詳細は references/common-errors.md を参照。

Migration Strategy

段階的移行アプローチ

  1. Phase 1: 現状把握

    bash
    # プロジェクト分析スクリプトを実行
    bash scripts/swift6-migration-analyzer.sh /path/to/project
    
  2. Phase 2: targeted で有効化

    • SWIFT_STRICT_CONCURRENCY = targeted に設定
    • 明示的に @Sendable をマークした箇所のみ警告
  3. Phase 3: 主要な型を修正

    • ViewModel → @MainActor を追加
    • 共有データ → actor に変換
    • 不変データ → Sendable に準拠
  4. Phase 4: complete で有効化

    • SWIFT_STRICT_CONCURRENCY = complete に設定
    • すべての警告を解消
  5. Phase 5: Swift 6 に移行

    • .swiftLanguageMode(.v6) を設定

Before/After 例

swift
// BEFORE: Swift 5 スタイル
class ViewModel: ObservableObject {
    @Published var items: [Item] = []

    func load() {
        Task {
            items = try await api.fetch()
        }
    }
}

// AFTER: Swift 6 スタイル
@Observable
@MainActor
class ViewModel {
    var items: [Item] = []

    func load() async {
        items = try await api.fetch()
    }
}

詳細は references/migration-checklist.md を参照。

Additional Resources

Example Files

Reference Files

Utility Scripts