关于 swift-formatstyle
swift-formatstyle 是一项开发技能,指导使用 Swift 的类型安全格式化与解析 API。内容涵盖本地化显示、SwiftUI 集成,以及跨代表性地区设置测试呈现结果。
主要功能
- 01选择内置 FormatStyle API
- 02用匹配样式解析格式化输入
- 03在 SwiftUI 中用 Text(_:format:) 格式化
- 04跨代表性地区设置检查输出
- 05内置样式不足时创建自定义样式
适用场景
- 01本地化日期、数字、货币和度量值
- 02接收需要往返解析的用户输入
- 03检查不同地区设置下的格式化界面
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill swift-formatstyle安装后在 Claude Code 中输入/swift-formatstyle确认已加载。
附带文件evals/evals.jsonreferences/formatstyle-recipes.md
详细介绍
Swift FormatStyle
使用 Foundation 类型安全的 FormatStyle API 来面向用户显示内容;当同一格式约定也必须接受输入时,使用 ParseableFormatStyle。String Catalog、复数形式、本地化文案、Bundle 和 RTL 布局请交由 ios-localization 处理;即使没有翻译任何文本,格式设置仍需经过区域设置审核。
目录
工作流
- 确定值的语义类型,以及输出是仅用于显示还是必须支持往返解析。
- 选择范围最窄的内置样式;除非线格式明确要求使用其他区域设置,否则保留用户当前的区域设置。
- 使用具有代表性的区域设置(如
en_US、de_DE、ar_SA和ja_JP)渲染实际 UI。 - 检查分隔符、数字系统、日历、货币和单位约定、文本方向及布局。
- 如果输出或解析失败,修正样式或周边文案,恢复输入测试数据,然后重新运行相同的区域设置矩阵。
实现需要具体修饰符、日期区间、相对日期、时长模式、度量、姓名、列表、字节数或 URL 组件控制时,请加载 FormatStyle Recipes。
快速参考
| 值 | 默认样式 | 重要限制 |
|---|---|---|
Int、Double | .number | 仅在需要时配置精度、舍入、分组、记数法或正负号。 |
Decimal | .number、.percent、.currency(code:) | 精确的十进制显示和解析优先使用此类型。 |
| 货币 | .currency(code:) | 传入 ISO 4217 代码;切勿硬编码货币符号。 |
| 百分比 | .percent | 确认输入是分数(0.85)还是整数百分比(85)。 |
Date | .dateTime、.relative、.interval | 相对日期通常应独立显示,而非嵌入句子中。 |
Duration | .time(pattern:)、.units(allowed:width:) | 需要 iOS 16+;根据需要选择紧凑时钟格式或带标签的单位。 |
Measurement | .measurement(width:usage:) | usage: 控制符合区域设置的换算策略。 |
PersonNameComponents | .name(style:) | 不要手动拼接姓名各部分。 |
| 集合 | .list(type:width:) | 让区域设置规则决定分隔符和连接词。 |
| 字节数 | .byteCount(style:) | 明确选择文件、内存、十进制或二进制语义。 |
URL | .url | 需要 iOS 16+;查询、端口和片段是可选的显示组件。 |
选择与可用性
- 对于新的 iOS 15+ 代码,优先使用
FormatStyle,而不是旧版NumberFormatter、DateFormatter、DateComponentsFormatter和手动插值。 Duration格式样式和URL.FormatStyle需要 iOS 16+。Date.AnchoredRelativeFormatStyle需要 iOS 18+,其格式以固定锚点为基准,而非当前时刻。- 常规 UI 中省略
.locale(...),让样式继承用户的区域设置。仅在协议明确要求或测试数据需要时使用固定区域设置。 - 除非整个句子都已围绕相对日期进行本地化,否则应将相对日期作为独立文本处理。
文档:FormatStyle
解析
用户需要编辑或导入已格式化的值时,使用匹配的可解析样式:
let style = Decimal.FormatStyle.Currency(code: "USD")
.locale(Locale(identifier: "en_US"))
let value = try Decimal("$3,500.63", format: style)
let display = value.formatted(style)
上面的固定区域设置仅适用于输入约定明确规定为 en_US 的情况。对于常规 UI 输入,应使用用户的区域设置,并使用具有代表性的十进制分隔符、货币位置、日历和数字系统测试往返转换。
SwiftUI 集成
优先使用 Text(_:format:),让 SwiftUI 管理格式化后的值:
Text(price, format: .currency(code: currencyCode))
Text(date, format: .dateTime.month().day().year())
Text(duration, format: .units(allowed: [.minutes, .seconds]))
对于每个面向用户的格式化 Text,都应在区域设置矩阵中预览或测试实际屏幕。对于实时更新的时间显示,请使用 Text(.now, style: .timer)、Text(.now, style: .relative) 或 Text(timerInterval:),而不是手动安排字符串刷新。
自定义 FormatStyle
仅当内置组合无法表达领域惯例时,才创建自定义样式。FormatStyle 继承了 Codable 和 Hashable;应将样式作为可复用的值,仅在输入必须支持往返解析时才添加 ParseableFormatStyle。
struct AbbreviatedCountStyle: FormatStyle {
func format(_ value: Int) -> String {
switch value {
case ..<1_000: "\(value)"
case 1_000..<1_000_000: String(format: "%.1fK", Double(value) / 1_000)
default: String(format: "%.1fM", Double(value) / 1_000_000)
}
}
}
extension FormatStyle where Self == AbbreviatedCountStyle {
static var abbreviatedCount: Self { .init() }
}
自定义样式仍需进行区域设置和无障碍审核;简短的英文后缀未必适用于所有区域设置。
常见错误
| 错误 | 修正方法 |
|---|---|
| 在视图代码中手动格式化或分配旧式格式化器 | 使用匹配的 FormatStyle 和 Text(_:format:)。 |
| 硬编码货币符号或区域设置 | 传入 ISO 货币代码,并沿用用户的区域设置,除非约定另有要求。 |
| 对精确十进制输入使用二进制浮点数 | 使用 Decimal.FormatStyle 及其对应的解析策略。 |
认为 URL.formatted() 会保留所有组件 | 仅当这些组件应显示时,才显式启用 .port(.always)、.query(.always) 或 .fragment(.always)。 |
| 将相对日期输出嵌入较长的句子 | 单独显示,或对完整句子进行本地化。 |
| 在行文中使用时钟样式的时长 | 对带标签的输出使用 .units(allowed:width:)。 |
| 未明确指定测量值转换方式 | 选择适合 UI 的 usage:。 |
| 只抽查一种区域设置 | 使用相同的实际屏幕测试样例检查多个有代表性的区域设置,并修复后重新运行失败项。 |
审核清单
- 已确定语义值类型,以及需要显示还是解析
- 在能够表达相关惯例时使用内置
FormatStyle - 在 iOS 16+ 和 iOS 18+ API 旁设置可用性限制
- 货币使用 ISO 4217 代码;精确十进制值使用
Decimal - 除非协议明确规定,否则沿用用户的区域设置
- 相对日期文本单独显示,或对完整句子进行本地化
- 明确设置 URL 组件和测量值的
usage: - SwiftUI 对格式化值使用
Text(_:format:) - 实际渲染的 UI 和解析往返均通过有代表性的区域设置矩阵测试
参考资料
- 详细示例和修饰符:references/formatstyle-recipes.md
- Apple 文档:FormatStyle · ParseableFormatStyle · Date.FormatStyle · Duration.TimeFormatStyle · URL.FormatStyle