关于 modern-swift
面向采用 Swift 6.2 和严格编译期检查的开发者的现代 Swift 并发指南,介绍 async/await、actor、任务组、取消处理及旧模式迁移。
主要功能
- 01async/await 并发模式
- 02使用 actor 管理共享可变状态
- 03任务组与取消处理
- 04严格并发与 Sendable 指引
- 05从旧式并发模式迁移
适用场景
- 01将完成回调替换为 async/await
- 02在不使用锁的情况下管理共享状态
- 03运行并行异步操作
- 04启用严格并发并处理 Sendable 错误
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ johnrogers/ claude-swift-engineering --skill modern-swift安装后在 Claude Code 中输入/modern-swift确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/concurrency-essentials.mdmacros.mdmigration-patterns.mdmodern-attributes.mdstrict-concurrency.mdswift6-concurrency.mdtask-cancellation.mdtask-groups.md详细介绍
Modern Swift(6.2+)
Swift 6.2 引入了严格的编译时并发检查,通过 async/await、actor 和 Sendable 约束在编译时而非运行时防止数据竞争。这是实现安全并发 Swift 的基础。
概览
Modern Swift 以编译器强制的安全机制取代了旧式并发模式(完成处理器、DispatchQueue、锁)。核心原则:启用严格并发检查后,只要代码能够编译,就不会发生数据竞争。
快速参考
| 需求 | 使用 | 不要使用 |
|---|---|---|
| 异步操作 | async/await | 完成处理器 |
| 主线程工作 | @MainActor | DispatchQueue.main |
| 共享可变状态 | actor | 锁、串行队列 |
| 并行任务 | TaskGroup | DispatchGroup |
| 线程安全 | Sendable | 到处使用 @unchecked |
核心工作流
编写 Swift 异步代码时:
- 用
async标记异步函数,并用await调用 - 对视图模型和更新 UI 的代码使用
@MainActor - 使用
actor而非锁来管理共享可变状态 - 在循环中检查
Task.isCancelled或调用Task.checkCancellation() - 在 Package.swift 中启用严格并发检查,以确保编译时安全
参考资料加载指南
只要有哪怕一点可能需要用到相关内容,就务必加载参考文件。 与其遗漏某种模式或犯错,不如先获取相关上下文。
| 参考资料 | 加载时机 |
|---|---|
| 并发基础 | 编写异步代码、转换完成处理器或使用 await 时 |
| Swift 6 并发 | 使用 @concurrent、nonisolated(unsafe) 或 actor 模式时 |
| 任务组 | 并行运行多个异步操作时 |
| 任务取消 | 实现长时间运行或可取消的操作时 |
| 严格并发检查 | 启用 Swift 6 严格模式或修复 Sendable 错误时 |
| 宏 | 使用或了解 @Observable 等 Swift 宏时 |
| 现代属性 | 迁移旧代码或使用 @preconcurrency、@backDeployed 时 |
| 迁移模式 | 改造代理模式或 UIKit 视图时 |
常见错误
-
把
@unchecked Sendable当作快速修复方案 — 使用@unchecked Sendable消除编译器错误,意味着你放弃了安全保证。如果使用@unchecked后错误仍然存在,说明代码可能存在数据竞争。应修复根本问题。 -
调用处漏写
await— 调用异步函数时忘记写await会导致编译错误;但在循环中检查Task.isCancelled却不调用Task.checkCancellation(),则会悄然忽略取消信号。 -
在异步代码块中未使用
weak捕获self— 在长时间运行的异步任务中持有对self的强引用,会阻止 deinit。始终在闭包中使用[weak self],或使用.task自动管理生命周期。 -
未检查任务取消状态 — 长时间运行的操作应定期检查
Task.isCancelled或调用Task.checkCancellation(),否则会忽略取消信号。 -
UI 代码和测试套件忘记添加
@MainActor— 更新@Published属性的主测试结构体和视图模型需要使用@MainActor。忘记添加会悄然允许跨线程修改。以下内容应使用@MainActor:视图模型、视图结构体、主测试结构体,以及任何访问 UI 的类型。 -
意外的 Actor 重入行为 — 在 actor 方法中使用
await可能会暂时释放锁。其他任务可能会修改 actor 状态。设计 actor 方法时,应假设状态在不同的await之间可能发生变化。