关于 axiom-swift-modern
面向 Swift 开发者的编码技能,提供现代 API、语法和并发实践以替代旧式或常见的生成模式,并强调边缘情况与安全默认值。
主要功能
- 01现代 Foundation API 替换建议
- 02简洁的现代 Swift 语法
- 03SwiftUI 便捷 API 指引
- 04Swift 6.3 并发默认实践
- 05避免不安全绕行方案的建议
适用场景
- 01改写使用旧 API 的代码
- 02检查生成的 Swift 是否采用过时模式
- 03选择并发与 Actor 隔离方式
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-swift-modern安装后在 Claude Code 中输入/axiom-swift-modern确认已加载。
详细介绍
现代 Swift 惯用写法
目的
Claude 经常根据训练数据生成过时的 Swift 写法。本技能会纠正常见问题——这些写法虽然可以正常编译,但使用了旧版 API,而现代替代方案更清晰、更高效或更正确。
理念:“不要重复 LLM 已经知道的内容——专注于边缘情况、意外之处和不太明显的弃用。”(Paul Hudson)
现代 API 替代方案
| 旧写法 | 现代 Swift | 起始版本 | 原因 |
|---|---|---|---|
Date() | Date.now | 5.6 | 意图更明确 |
filter { }.count | count(where:) | 5.0 | 只遍历一次,无中间分配 |
replacingOccurrences(of:with:) | replacing(_:with:) | 5.7 | Swift 原生 API,无需桥接到 Foundation |
CGFloat | Double | 5.5 | 隐式桥接;例外情况:可选值、inout、与 Objective-C 桥接的 API |
Task.sleep(nanoseconds:) | Task.sleep(for: .seconds(1)) | 5.7 | 类型安全的 Duration API |
DateFormatter() | .formatted() / FormatStyle | 5.5 | 无需管理实例,默认支持本地化 |
String(format: "%.2f", val) | val.formatted(.number.precision(.fractionLength(2))) | 5.5 | 类型安全,支持本地化 |
localizedCaseInsensitiveContains() | localizedStandardContains() | 5.0 | 可处理变音符号、连字和宽度变体 |
"\(firstName) \(lastName)" | 使用 PersonNameComponents 和 .formatted() | 5.5 | 遵循地区设置中的姓名顺序 |
使用 DateFormatter 处理 "yyyy-MM-dd" | try Date(string, strategy: .iso8601) | 5.6 | 现代解析方式(会抛出错误);显示时使用 "y",而不是 "yyyy" |
对用户输入使用 contains() | localizedStandardContains() | 5.0 | 正确搜索或筛选文本的必要做法 |
现代语法
| 旧写法 | 现代 Swift | 起始版本 |
|---|---|---|
if let value = value { | if let value { | 5.7 |
单表达式中的显式 return | 省略 return;if/switch 是表达式 | 5.9 |
修饰符中的 Circle() | .circle(静态成员查找) | 5.5 |
同时 import UIKit 和 import SwiftUI | 通常不需要——SwiftUI 会重新导出大多数 UIKit/AppKit 类型。UIKit 专用 API(如 UIApplication)仍需保留 | 5.5 |
Foundation 现代化
| 旧写法 | 现代 Foundation | 起始版本 |
|---|---|---|
FileManager.default.urls(for: .documentDirectory, ...) | URL.documentsDirectory | 5.7 |
url.appendingPathComponent("file") | url.appending(path: "file") | 5.7 |
重复使用 books.sorted { $0.author < $1.author } | 遵循 Comparable,调用 .sorted() | — |
用于显示的日期格式 "yyyy" | "y"——适用于所有日历系统 | — |
Claude 容易忽略的 SwiftUI 便捷 API
ContentUnavailableView.search(text: searchText)(iOS 17+)会自动包含搜索词——无需拼接自定义字符串Form中的LabeledContent(iOS 16+)无需手动使用 HStack 布局,即可让标签对齐方式保持一致confirmationDialog()必须附加到触发它的 UI 上——Liquid Glass 的形变动画依赖源元素
Swift 6.3 并发实践准则
编写以 Swift 6.3 为首选的代码,不要沿用 Swift 5 时代的写法。这些默认规则适用于所有新 Swift 代码,而不只是出现并发错误时。
| 默认规则 | 理由 |
|---|---|
| 假设启用严格并发,并在应用/UI 模块中默认隔离到 MainActor | Swift 6.3 语言模式;Xcode 26+ 新项目的默认设置 |
| 优先使用 async/await,而不是 GCD、DispatchGroup 和层层嵌套的回调 | GCD 是用于兼容旧 API 的桥接模式,不是默认架构 |
异步不代表在后台运行——使用 @concurrent(Swift 6.2+)强制在主线程外运行 | 异步函数会在调用它们的同一个 actor 上恢复执行 |
优先使用结构化并发(async let、TaskGroup),而不是非结构化的 Task {} | 结构化任务会自动传播取消和错误 |
除非有明确说明的特定理由,否则不要使用 Task.detached | 它会丢失 actor 上下文、优先级和任务局部值 |
| 对跨 actor 边界传递的数据,优先使用 Sendable 结构体/枚举 | 值类型天然可以安全共享 |
| 仅在并发域之间确实存在共享可变状态时才使用 actor | 不要让每个类都变成 actor——UI 代码应保持为 @MainActor |
将 @unchecked Sendable、@preconcurrency、nonisolated(unsafe) 视为临时桥接工具 | 每项都应有对应的移除任务,不应永久保留 |
| 不要只为消除编译器错误而添加逃生口 | 它们会掩盖可能导致生产环境崩溃的数据竞争 |
如需了解详细模式、决策树和针对特定错误的指导,请参阅 axiom-swift-concurrency。
Claude 常见幻觉
Claude 生成的代码中经常出现以下模式:
- 内联创建
DateFormatter实例——改用.formatted()或FormatStyle。如果必须使用格式化器,请将其声明为static let。 - 使用
DispatchQueue.main.async——改用@MainActor或MainActor.run。GCD 是桥接模式,不是默认做法。 - 使用
DispatchQueue.global().async执行后台任务——改用@concurrent(Swift 6.2+)或将任务提取到 actor 中。 - 使用
Task.detached来“让任务在后台运行”——改用@concurrent。Task.detached会丢失 actor 上下文。 - 在 SwiftUI 参数中使用
CGFloat——自 Swift 5.5 起,隐式桥接使Double在所有场景中都可用。 - 生成
guard let x = x else——改用简写形式guard let x else。 - 在单表达式计算属性中显式使用
return——省略return。 - 在循环中创建非结构化的
Task {}——对动态并行任务使用TaskGroup。 - 添加
@unchecked Sendable来消除警告——改用 actor 或符合 Sendable 的类型。
资源
技能:axiom-swift-performance、axiom-swift-concurrency、axiom-swiftui-architecture
评论
支持 Markdown