SuperAPI AI 工具集

write-swift

编程与开发

查看项目

更新于 10-15 08:33

技能介绍

write-swift 是一个面向 Swift 开发者的写作与编码指导技能,主题是“如何以 Swift 语言期望的方式编写现代 Swift”,内容更新至 Swift 6.4。其工具链基线为 Swift 6.3(资料称其为 2026 年 8 月的当前版本),标注 ⚠ 的内容为尚未发布的 Swift 6.4 特性;并发指导基于 Swift 6.2 模型,若项目使用 6.1 或更早版本,则关于 async 与 @concurrent 的规则不适用。

核心理念:Swift 是一门渐进式披露(progressive-disclosure)语言。应从最简单、最静态、最单线程且可行的方案开始,只有在能明确指出理由时才引入动态特性——并发、引用语义、存在类型、不安全指针。资料给出一个默认层级:数据默认用 struct / enum,仅在需要身份、共享或继承时才用 class;抽象默认用具体类型,仅在跨类型出现重复代码时才抽象;多态默认用 some P(泛型),仅在需要异构存储时才用 any P;执行默认在主 actor 上同步进行,仅在性能分析显示卡顿后才依次引入 async、@concurrent、actor;内存默认用 Array、String,仅在性能分析显示成本后才用 InlineArray、Span;安全默认用安全 API,仅在 C 互操作或实测热路径中才用 Unsafe*。

主要能力与内容分段:

  1. 用值类型建模数据。默认使用 struct 和 enum,class 仅用于身份、共享可变状态、继承或资源生命周期。默认用 let,仅在需要修改时用 var。含可变引用类型属性的 struct 既非值也非引用,需保持被引用类型不可变、只暴露转发计算属性,或将其设为私有存储属性并配合写时复制(copy-on-write)。写时复制通过将 final class 包装进 struct 并在修改前检查 isKnownUniquelyReferenced(&storage) 实现,Array、String、Dictionary 即如此工作。enum 用于“固定集合”和互斥状态,可把一堆可选存储属性替换为单一 State 枚举,使非法组合不可表示、状态变更原子化。非可复制类型(~Copyable)表达唯一所有权,如文件描述符、银行转账、打开的资源,可将“不得运行两次”从断言变为编译错误,并使 struct 的 deinit 有意义;完成方法标记为 consuming 以让编译器证明其为最后一次使用。

  2. 错误与可选值。可恢复错误用 throw,程序员错误用 precondition/fatalError。带关联值的 enum 最适合做错误类型。guard 用于错误条件以强制退出路径,if let 用于普通解包。类型化 throws(throws(MyError))适用于内部函数、错误转发泛型代码和受限环境;公共 API 用非类型化 throws 以保留日后更改错误类型的自由。仅在能说明不变式时强制解包,并优先使用带消息的 #require/precondition 而非裸 !。

  3. 并发:在性能分析表明必要之前保持单线程。资料强调这是智能体最常出错的章节,因为模型在 Swift 6.2 发生了变化。建议每个应用都从完全在主线程开始,按顺序推进:主 actor 上单线程 → async/await 隐藏延迟 → @concurrent 将昂贵工作移出主线程(仅在 Instruments 显示卡顿后)→ actor 将状态移出主 actor(仅当过多主 actor 状态迫使任务频繁跳转时)。构建设置方面,建议在每个项目启用 Approachable Concurrency;应用模块和面向 UI 的模块将 Default Actor Isolation 设为 MainActor(Xcode 26 新应用项目的默认值),包中写作 swiftSettings: [.defaultIsolation(MainActor.self)];通用库不应设置 main-actor-by-default。规则变化:在 Swift 6.2 中,将函数标记为 async 不会将其移出当前 actor,它就在调用处运行;@concurrent 总是切换到并发线程池;nonisolated 在调用处运行,是库 API 的合适默认;两者都不加则留在调用者的 actor 上。资料还强调先分析再卸载、不要为琐碎工作创建任务、每个端到端操作一个任务、await 是挂起点会破坏原子性、actor 重入(actor 保证互斥而非事务,同步方法构成事务边界,actor 非 FIFO)。

  4. Sendable 与数据共享。Sendable 标记类型可安全跨隔离域共享,编译器在每个任务和 actor 边界检查。值类型在其存储满足条件时自动推断 Sendable(非公共类型);公共类型从不自动推断。actor 和 @MainActor 类隐式 Sendable。多数模型类应既非 @MainActor 也非 Sendable,若需离开主 actor 应设为 nonisolated。非 Sendable 对象只要发送方停止使用仍可跨域传递。遇到数据竞争错误时的排查顺序:不共享 → 改为 Sendable 值类型 → 隔离到 actor → 最后才用 Mutex/Atomic 或 @unchecked Sendable。全局与静态变量是最常见错误来源,优先级为 let → @MainActor → Mutex → nonisolated(unsafe)。

  5. 结构化并发。优先使用结构化任务(async let、任务组),它们像局部变量一样有作用域、自动等待、继承取消/优先级/任务局部值。async let 用于固定数量的并发子任务;withTaskGroup 用于动态数量;withDiscardingTaskGroup 用于子任务无返回值时。Task { } 仅用于生命周期不适合作用域的场景;Task.detached 几乎不用。取消是协作式的,需检查 Task.isCancelled 或 try Task.checkCancellation()。应限制并发数量,不要对无界列表每项派生一个子任务。任务局部值(@TaskLocal)用于传播上下文。桥接回调用 withCheckedContinuation / withCheckedThrowingContinuation,契约是每条路径恰好 resume 一次。AsyncSequence 用 for await / for try await 迭代,用 AsyncStream / AsyncThrowingStream 适配回调或委托 API。

  6. SwiftUI 中的并发。View 及其包含的 @State 都是 @MainActor 隔离的,几乎不需要写 @MainActor。SwiftUI 有意让部分代码在主线程外运行,信号是 API 签名中的 @Sendable(如 visualEffect、Shape.path(in:)、Layout 要求、onGeometryChange);遇到隔离错误时不要发送 self,而应把所需值复制进闭包捕获列表。SwiftUI 的动作回调是同步的,时间敏感的 UI 更新应在同一帧完成,仅对后续长任务开启 Task。建议把状态放在 UI 与异步工作的接缝处。

  7. 协议与泛型。不要从 class 开始,也不要从协议开始。工作流是:写具体类型 → 发现跨类型重复代码 → 将共享能力提取为协议 → 针对它写泛型代码。没有按类型定制的协议是浪费的协议;若每个遵循都用相同默认实现,应改为对现有协议的约束扩展。优先 has-a 而非 is-a;若协议只有部分操作对类型有意义,不要细化协议,而应包装进泛型 struct 并只暴露所需 API。

使用方式:该技能在被首次调用且没有具体问题时,仅回复“I'm ready to help you write modern Swift, the way the language wants to be written.”,在用户提问前不提供其他信息。

适用场景:编写或审查现代 Swift 代码,尤其是涉及值类型建模、Swift 6 数据竞争安全、并发与 actor、Sendable、结构化并发、SwiftUI 并发以及协议与泛型设计的场景。

限制:资料未提供该技能的安装命令、收费方式、价格、平台支持或效果数据,这些信息暂未提供。