🚀 快速安装

复制以下命令并运行,立即安装此 Skill:

npx skills add https://github.com/avdlee/swift-concurrency-agent-skill --skill swift-concurrency

💡 提示:需要 Node.js 和 NPM

Swift 并发

代理规则

  1. 在给出建议之前,先分析 Package.swift.pbxproj 以确定 Swift 语言模式(5.x 还是 6)和工具链。
  2. 在提出修复方案之前,先识别隔离边界:@MainActor、自定义 actor、actor 实例隔离或 nonisolated
  3. 不要将 @MainActor 作为通用修复方案推荐。必须说明主 actor 隔离对代码是正确的原因。
  4. 优先使用结构化并发(子任务、任务组),而不是非结构化任务。仅在明确理由下使用 Task.detached
  5. 如果推荐使用 @preconcurrency@unchecked Sendablenonisolated(unsafe),必须满足:
    • 有文档记录的安全不变性
    • 一个后续移除或迁移的待办任务
  6. 对于迁移工作,以最小影响范围为目标(小的、可审查的更改),并遵循验证循环:构建 → 修复错误 → 重新构建 → 仅当无错误时继续
  7. 课程参考资料仅用于深入学习。仅在它们能明显帮助回答开发者问题时才谨慎使用。

初步诊断清单(提供建议前)

  • 获取确切的编译器诊断信息和导致问题的符号。
  • 识别当前的隔离边界和模块默认设置(@MainActor、自定义 actor、默认隔离)。
  • 确认代码是与 UI 绑定,还是设计为在主 actor 之外运行。

快速修复模式(何时使用)

当满足以下条件时,使用快速修复模式:

  • 错误是局部的(单个文件或单个类型),且隔离边界清晰。
  • 修复不需要重新设计 API 或多模块更改。
  • 你可以用 1-2 个步骤解释修复方案,且不改变行为。

当满足以下条件时,跳过快速修复模式:

  • 默认隔离或严格并发设置未知,且可能影响行为。
  • 错误跨越模块边界或涉及公开 API 更改。
  • 修复方案需要 @unchecked Sendable@preconcurrencynonisolated(unsafe),但没有清晰的不变性保证。

项目设置检查(提供建议前评估)

并发行为取决于构建设置。在提供建议前,通过读取 Package.swift 或在 .pbxproj 文件中搜索来确定这些设置:

设置项 SwiftPM (Package.swift) Xcode (.pbxproj)
默认隔离 .defaultIsolation(MainActor.self) SWIFT_DEFAULT_ACTOR_ISOLATION
严格并发检查 .enableExperimentalFeature("StrictConcurrency=targeted") SWIFT_STRICT_CONCURRENCY
即将推出的功能 .enableUpcomingFeature("NonisolatedNonsendingByDefault") SWIFT_UPCOMING_FEATURE_*
语言模式 文件顶部的 // swift-tools-version: Swift 语言版本构建设置

如果其中任何一项未知,在给出受迁移影响的指导前,要求开发者确认它们。

最安全的微小修复(快速见效)

优先选择在满足数据竞争安全的同时,保留行为的修改。

  • UI 绑定的类型:将类型或特定成员隔离到 @MainActor(说明为何是 UI 绑定)。
  • 全局/静态可变状态:移入 actor 或隔离到 @MainActor(如果仅用于 UI)。
  • 后台工作:对于应始终从调用者的隔离环境跳出的工作,将开销大的工作移入标记为 @concurrentasync 函数中;对于不触碰隔离状态但可以继承调用者隔离的工作(例如使用 NonisolatedNonsendingByDefault 时),使用 nonisolated 而无需 @concurrent,或者使用 actor 来保护可变状态。
  • Sendable 错误:优先使用不可变/值类型;避免使用 @unchecked Sendable,除非你能证明并记录线程安全性。

快速修复手册(常见诊断 -> 最小修复)

  • “Main actor-isolated … cannot be used from a nonisolated context”
    • 快速修复:如果与 UI 绑定,使调用方成为 @MainActor 或使用 await MainActor.run { ... } 进行跳转。
    • 如果这是非 UI 代码或会导致重入性问题,则升级处理;使用 references/actors.md
  • “Actor-isolated type does not conform to protocol”
    • 快速修复:添加隔离的一致性声明(例如,extension Foo: @MainActor SomeProtocol)。
    • 如果协议要求必须是 nonisolated,则升级处理;使用 references/actors.md
  • “Sending value of non-Sendable type … risks causing data races”
    • 快速修复:在 actor 内部限制访问,或转换为具有不可变 (let) 状态的值类型。
    • 在使用 @unchecked Sendable 前升级处理;使用 references/sendable.mdreferences/threading.md
  • SwiftLint async_without_await
    • 快速修复:如果不需要 async 则移除;如果协议/重写/@concurrent 需要,则使用带理由的局部抑制。参见 references/linting.md
  • “wait(…) is unavailable from asynchronous contexts” (XCTest)
    • 快速修复:使用 await fulfillment(of:) 或 Swift Testing 的等效方法。参见 references/testing.md

升级处理路径(当快速修复不够用时)

  1. 收集项目设置(默认隔离、严格并发级别、即将推出的功能)。
  2. 重新评估隔离边界以及哪些类型跨越了这些边界。
  3. 使用决策树 + 参考文档进行更深入的修复。
  4. 如果行为可能发生变化,记录不变性并添加测试/验证步骤。

快速决策树

当开发者需要并发指导时,遵循此决策树:

  1. 开始编写新的异步代码?
    • 阅读 references/async-await-basics.md 了解基础模式
    • 对于并行操作 → references/tasks.md(async let,任务组)
  2. 保护共享的可变状态?
    • 需要保护基于类的状态 → references/actors.md(actors, @MainActor)
    • 需要线程安全的值传递 → references/sendable.md(Sendable 一致性)
  3. 管理异步操作?
    • 结构化的异步工作 → references/tasks.md(Task,子任务,取消)
    • 流式数据 → references/async-sequences.md(AsyncSequence,AsyncStream)
  4. 使用遗留框架?
    • Core Data 集成 → references/core-data.md
    • 通用迁移 → references/migration.md
  5. 性能或调试问题?
    • 异步代码慢 → references/performance.md(性能分析,挂起点)
    • 测试相关问题 → references/testing.md(XCTest,Swift Testing)
  6. 理解线程行为?
    • 阅读 references/threading.md 了解线程/任务关系和隔离
  7. 任务的内存问题?
    • 阅读 references/memory-management.md 了解如何防止循环引用

诊断优先手册(常见错误 -> 下一步最佳操作)

  • SwiftLint 并发相关警告
    • 使用 references/linting.md 了解规则意图和首选修复方案;避免使用虚假的 await 作为“修复”。
  • SwiftLint async_without_await 警告
    • 如果不需要 async 则移除;如果协议/重写/@concurrent 需要,则优先使用局部抑制而非添加假的 await。参见 references/linting.md
  • “Sending value of non-Sendable type … risks causing data races”
    • 首先:识别值在何处跨越隔离边界
    • 然后:使用 references/sendable.mdreferences/threading.md(特别是 Swift 6.2 的行为变化)
  • “Main actor-isolated … cannot be used from a nonisolated context”
    • 首先:判断它是否真的应该属于 @MainActor
    • 然后:使用 references/actors.md(全局 actor,nonisolated,隔离参数)和 references/threading.md(默认隔离)
  • “Class property ‘current’ is unavailable from asynchronous contexts” (线程 API)
    • 使用 references/threading.md 避免以线程为中心的调试,依赖隔离 + Instruments
  • “Actor-isolated type does not conform to protocol” (协议一致性错误)
    • 首先:确定协议要求是否必须在 actor 上执行(例如,在 @MainActor 上的 UI 工作),或者可以安全地标记为 nonisolated
    • 然后:遵循快速修复手册中关于 actor 隔离协议一致性的条目,以及 references/actors.md 中的实现模式(隔离的一致性声明,nonisolated 要求,以及升级步骤)。
  • XCTest 异步错误,如 “wait(…) is unavailable from asynchronous contexts”
    • 使用 references/testing.mdawait fulfillment(of:) 和 Swift Testing 模式)
  • Core Data 并发警告/错误
    • 使用 references/core-data.md(DAO/NSManagedObjectID,默认隔离冲突)

核心模式参考

并发工具选择

需求 工具 关键指导
单个异步操作 async/await 顺序异步工作的默认选择
固定数量的并行操作 async let 编译时数量已知;抛出时自动取消
动态数量的并行操作 withTaskGroup 数量未知;结构化的——作用域退出时取消子任务
同步 → 异步桥接 Task { } 继承 actor 上下文;仅在记录理由后使用 Task.detached
共享可变状态 actor 优于锁/队列;保持隔离部分小巧
UI 绑定的状态 @MainActor 仅用于真正与 UI 相关的代码;说明隔离理由

常见场景

带 UI 更新的网络请求

Task { @concurrent in
    let data = try await fetchData()
    await MainActor.run { self.updateUI(with: data) }
}

并行处理数组项

await withTaskGroup(of: ProcessedItem.self) { group in
    for item in items {
        group.addTask { await process(item) }
    }
    for await result in group {
        results.append(result)
    }
}

Swift 6 迁移快速指南

Swift 6 的主要变化:

  • 严格并发检查 默认启用
  • 编译时完整的数据竞争安全
  • Sendable 要求 在边界上强制执行
  • 隔离检查 针对所有异步边界

迁移验证循环

对每个迁移更改应用此循环:

  1. 构建 — 运行 swift build 或 Xcode 构建以显示新的诊断信息
  2. 修复 — 一次处理一类错误(例如,先处理所有 Sendable 问题)
  3. 重新构建 — 在继续之前确认修复编译无误
  4. 测试 — 运行测试套件以捕获回归问题(swift test 或 Cmd+U)
  5. 仅在解决所有诊断后 才继续处理下一个文件/模块

如果修复引入了新的警告,在继续之前解决它们。切勿批量处理不相关的修复——保持提交小巧且可审查。

有关详细的迁移步骤,请参见 references/migration.md

参考文件

根据需要加载这些文件以获取特定主题:

  • async-await-basics.md – async/await 语法、执行顺序、async let、URLSession 模式
  • tasks.md – 任务生命周期、取消、优先级、任务组、结构化与非结构化
  • threading.md – 线程/任务关系、挂起点、隔离域、nonisolated
  • memory-management.md – 任务中的循环引用、内存安全模式
  • actors.md – Actor 隔离、@MainActor、全局 actor、重入性、自定义执行器、Mutex
  • sendable.md – Sendable 一致性、值/引用类型、@unchecked、区域隔离
  • linting.md – 专注于并发的代码检查规则和 SwiftLint async_without_await
  • async-sequences.md – AsyncSequence、AsyncStream、何时使用 vs 常规 async 方法
  • core-data.md – NSManagedObject 的可发送性、自定义执行器、隔离冲突
  • performance.md – 使用 Instruments 进行性能分析、减少挂起点、执行策略
  • testing.md – XCTest 异步模式、Swift Testing、并发测试工具
  • migration.md – Swift 6 迁移策略、闭包到 async 的转换、@preconcurrency、FRP 迁移

验证清单(当你更改并发代码时)

  1. 在解释诊断信息之前,确认构建设置(默认隔离、严格并发、即将推出的功能)。
  2. 构建 — 验证项目编译无误,没有新的警告或错误。
  3. 测试 — 运行测试,尤其是对并发敏感的测试(参见 references/testing.md)。
  4. 性能 — 如果与性能相关,使用 Instruments 验证(参见 references/performance.md)。
  5. 生命周期 — 如果与生命周期相关,验证 deinit/取消行为(参见 references/memory-management.md)。
  6. 在长时间运行的操作中检查 Task.isCancelled
  7. 切勿在异步上下文中使用信号量或锁——改用 actor 或 Mutex

术语表

参见 references/glossary.md 快速了解本技能中使用的核心并发术语定义。


注意:此技能基于 Antoine van der Lee 的综合课程 Swift 并发课程

📄 原始文档

完整文档(英文):

https://skills.sh/avdlee/swift-concurrency-agent-skill/swift-concurrency

💡 提示:点击上方链接查看 skills.sh 原始英文文档,方便对照翻译。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。