名称: swift-best-practices 描述: 该技能应在为iOS或macOS项目编写或审查Swift代码时使用。应用现代Swift 6+最佳实践、并发模式、API设计指南和迁移策略。涵盖async/await、actors、MainActor、Sendable、类型化throws和Swift 6破坏性变更。
Swift最佳实践技能
概述
应用现代Swift开发最佳实践,专注于Swift 6+特性、并发安全性、API设计原则以及针对macOS 15.7+的iOS和macOS项目的代码质量指南。
何时使用此技能
在以下情况使用此技能:
- 为iOS或macOS应用程序编写新的Swift代码
- 审查Swift代码的正确性、安全性和风格
- 实现Swift并发特性(async/await、actors、MainActor)
- 设计Swift API和公共接口
- 将代码从Swift 5迁移到Swift 6
- 解决并发警告、数据竞争问题或与Sendable/隔离相关的编译器错误
- 使用Swift 6和6.2中引入的现代Swift语言特性
核心指南
基本原则
- 使用时的清晰度至关重要 - 通过检查使用案例来评估设计,而不仅仅是声明
- 清晰胜于简洁 - 紧凑代码来自类型系统,而非最少字符
- 为每个公共声明编写文档 - 如果无法简单描述功能,API可能设计不佳
- 按角色命名,而非类型 -
var greeting = "Hello"而不是var string = "Hello" - 偏爱通过简单实现的优雅 - 避免过度工程,除非复杂性确实需要
Swift 6并发模型
Swift 6默认启用完整的并发检查,基于区域的隔离(SE-0414)。编译器现在证明代码安全性,消除许多误报,同时在编译时捕获真正的并发问题。
关键理解:
- Async ≠ 后台 - async函数可以暂停,但不自动在后台线程运行
- Actors通过自动同步保护可变共享状态
@MainActor确保UI相关代码在主线程执行- 全局actor隔离类型自动为
Sendable
基本模式
Async/Await
// 使用async let进行并行执行
func fetchData() async -> (String, Int) {
async let stringData = fetchString()
async let intData = fetchInt()
return await (stringData, intData)
}
// 在长时间运行的操作中始终检查取消
func process(_ items: [Item]) async throws -> [Result] {
var results: [Result] = []
for item in items {
try Task.checkCancellation()
results.append(await process(item))
}
return results
}
MainActor用于UI代码
// 在类型级别应用以实现一致的隔离
@MainActor
class ContentViewModel: ObservableObject {
@Published var images: [UIImage] = []
func fetchData() async throws {
self.images = try await fetchImages()
}
}
// 当直接await可行时,避免使用MainActor.run
await doMainActorStuff() // 好
await MainActor.run { doMainActorStuff() } // 不必要
Actor隔离
actor DataCache {
private var cache: [String: Data] = [:]
func store(_ data: Data, forKey key: String) {
cache[key] = data // 在actor内部无需await
}
nonisolated func cacheType() -> String {
return "DataCache" // 无需await - 不访问隔离状态
}
}
常见陷阱避免
- 不要不必要地将函数标记为
async- async调用约定有开销 - 永远不要将
DispatchSemaphore与async/await一起使用 - 死锁风险 - 不要创建无状态的actors - 使用非隔离async函数代替
- 避免分割隔离 - 不要在一个类型内混合隔离域
- 检查任务取消 - 长时间操作必须检查
Task.checkCancellation() - 不要假设async意味着后台 - 如果需要,明确将工作移到后台
- 避免过多的上下文切换 - 在同一隔离域内分组操作
API设计快速参考
命名约定
- 类型/协议:
UpperCamelCase - 其他:
lowerCamelCase - 描述能力的协议:
-able、-ible、-ing后缀(Equatable、ProgressReporting) - 工厂方法:以
make开头(x.makeIterator()) - 可变对:命令式vs过去分词(
x.sort()/x.sorted())
按副作用命名方法
- 无副作用:名词短语(
x.distance(to: y)) - 有副作用:命令式动词(
x.append(y)、x.sort())
参数标签
- 当参数无法区分时省略:
min(number1, number2) - 值保持转换省略第一个标签:
Int64(someUInt32) - 介词短语在介词处标签:
x.removeBoxes(havingLength: 12) - 标签所有其他参数
Swift 6破坏性变更
必须显式用@MainActor标记类型(SE-0401)
属性包装器不再自动推断actor隔离。
@MainActor
struct LogInView: View {
@StateObject private var model = ViewModel()
}
全局变量必须是并发安全的(SE-0412)
static let config = Config() // 常量 - 好
@MainActor static var state = State() // Actor隔离 - 好
nonisolated(unsafe) var cache = [String: Data]() // 不安全 - 谨慎使用
其他变更
@UIApplicationMain/@NSApplicationMain已弃用(使用@main)- 存在类型必须使用
any - 导入可见性需要显式访问控制
API可用性模式
// 基本可用性
@available(macOS 15, iOS 18, *)
func modernAPI() { }
// 带有消息的弃用
@available(*, deprecated, message: "使用newMethod()代替")
func oldMethod() { }
// 带有自动修复的重命名
@available(*, unavailable, renamed: "newMethod")
func oldMethod() { }
// 运行时检查
if #available(iOS 18, *) {
// iOS 18+代码
}
// 反向检查(Swift 5.6+)
if #unavailable(iOS 18, *) {
// iOS 17及以下
}
关键差异:
deprecated- 警告,允许使用obsoleted- 从特定版本起错误unavailable- 错误,完全阻止使用
如何使用此技能
编写代码时
- 应用命名约定,遵循基于角色、清晰优先的原则
- 使用适当的隔离(UI用
@MainActor,可变状态用actors) - 正确实现async/await模式,并处理适当的取消
- 遵循Swift 6并发模型 - 信任编译器的流分析
- 用清晰、简洁的摘要记录公共API
审查代码时
- 检查并发安全违规
- 验证适当的actor隔离和Sendable一致性
- 确保async函数正确处理取消
- 验证API命名遵循Swift指南
- 确认可用性注释对目标平台正确
代码质量标准
- 最小化注释 - 代码应尽可能自文档化
- 避免过度工程和不必要的抽象
- 使用基于角色的有意义的变量名,而非类型
- 遵循已建立的项目架构和模式
- 优先使用
count(where:)而非filter().count - 对固定大小、性能关键的数据使用
InlineArray - 信任编译器的并发流分析 - 避免不必要的
Sendable一致性
资源
参考/
当需要深入信息时加载的详细参考材料:
- api-design.md - 完整的API设计约定、文档标准、参数指南和命名模式
- concurrency.md - 详细的async/await模式、actor最佳实践、常见陷阱、性能考虑和线程安全模式
- swift6-features.md - Swift 6/6.2中的新语言特性、破坏性变更、迁移策略和现代模式
- availability-patterns.md - 全面的
@available属性使用、弃用策略和平台版本管理
当需要超出上述核心指南的详细信息时,加载这些参考。
平台要求
- Swift 6.0+编译器用于Swift 6特性
- Swift 6.2+用于InlineArray和增强的并发特性
- macOS 15.7+与适当的SDK
- iOS 18+用于最新的平台特性
- 使用
#available进行运行时平台检测 - 使用
@available进行API可用性标记