SwiftUI 专家技能 是做什么的?
操作规则
- 将每个
View类型视为一个失效边界:仅赋予它需要读取的数据,并将频繁变化的依赖项保持在受影响的最小子树附近。 - 在编写、审查或迁移 API 使用时,查阅
references/latest-apis.md;仅查找与任务相关的 API。 - 将硬弃用的 API 替换为现代等效项。在功能开发期间,标记软弃用的 API 并保留原样(见
references/soft-deprecation.md)。 - 除非必须桥接,否则优先使用原生 SwiftUI API 而非 UIKit/AppKit。
- 关注正确性和性能;不强制执行特定架构(如 MVVM、VIPER 等)。
- 鼓励将业务逻辑与视图分离以实现可测试性,但不强制规定方式。
- 遵循 Apple 人机界面指南和 API 设计模式。
- 仅在用户明确要求时才采用 Liquid Glass(见
references/liquid-glass.md)。 - 将性能优化作为建议而非要求提出。
- 对版本特定 API 使用
#available门控并提供合理的回退方案。 - 对于布局和渲染输入,读取最接近消耗该输入的 SwiftUI 视图的值;不要替代进程全局屏幕状态。
任务工作流
审查现有 SwiftUI 代码
- 阅读待审查的代码,确定适用的主题。
- 标记已弃用的 API(与
references/latest-apis.md对比);替换硬弃用的 API,并标记软弃用的 API 而不重写,除非用户要求迁移。 - 为每个相关主题运行下面的主题路由器。
- 验证
#available门控和版本特定功能的回退路径。 - 对于大范围代码库审查,首先确定较小的关注区域并逐一呈现;如果用户请求全代码库审查,则将其拆分为待办事项列表。
改进现有 SwiftUI 代码
- 对照主题路由器主题审查当前实现。
- 用
references/latest-apis.md中的现代等效项替换硬弃用的 API;在功能开发期间标记软弃用的 API 且不重写。 - 重构热路径以减少不必要的状态更新。
- 将复杂视图主体拆分为单独的子视图。
- 当遇到
UIImage(data:)时建议图像下采样(可选优化,见references/image-optimization.md)。
实现新的 SwiftUI 功能
- 首先设计数据流:识别拥有的状态与注入的状态。
- 为最佳差异比较构建视图(尽早提取子视图)。
- 应用正确的动画模式(隐式与显式、过渡)。
- 对所有可点击元素使用
Button;添加无障碍分组和标签。 - 使用
#available门控版本特定 API 并提供回退方案。
录制新的 Instruments trace
当用户要求“录制 trace”、“对应用进行性能分析”、“捕获会话”等时触发。完整参考:references/trace-recording.md。
- 确认目标 — 附加到正在运行的应用、启动应用还是录制所有进程?如果用户未说明,请询问。必要时列出已连接的设备:
python3 "${SKILL_DIR}/scripts/record_trace.py" --list-devices - 根据目标类型选择模板 —
SwiftUI模板会在任意真实设备上填充 SwiftUI 通道:物理 iOS/iPadOS 设备或主机 Mac。唯一的例外是 iOS 模拟器,其中 SwiftUI 通道为空 — 在这种情况下切换为--template "Time Profiler"(提供 Time Profiler + 挂起,但没有动画卡顿)。始终检查--list-devices:simulators类型 →Time Profiler;devices类型(真实设备和主机 Mac)→ 默认SwiftUI。完整决策表见references/trace-recording.md。 - 开始录制。对于由代理驱动的会话(用户表示“完成后我会告诉你”),在后台启动并使用停止文件:
对于交互式会话,只需告知用户在完成后按 Ctrl+C。python3 "${SKILL_DIR}/scripts/record_trace.py" \ --device "<名称|udid>" --attach "<应用名称>" \ --stop-file /tmp/stop-trace --output ~/Desktop/session.trace - 发出停止信号 — 当用户表示已完成应用操作时,执行
touch /tmp/stop-trace命令。脚本会干净地向 xctrace 发送 SIGINT 信号并等待最多 60 秒完成。 - 分析生成的 trace(流转到下面的“trace 驱动改进”工作流)。
Trace 驱动改进(提供了 Instruments .trace)
只要用户的请求引用了 .trace 文件就触发。目标 SwiftUI 源文件是可选的 — 如果提供了,则引用具体行号;如果没有,则根据 trace 已揭示的视图名称和符号推荐查看位置。
完整参考:references/trace-analysis.md。
**挂起:**如果 xctrace help 列出了 triage(Xcode 27.2 有此功能),则从 xctrace triage <trace> --style hangs 开始,然后使用 xctrace show 深入分析。集成的解析器仍然是处理卡顿、SwiftUI 更新、因果图以及日志或 signpost 窗口的工具。
解析器组合模式的摘要:
- **界定分析范围。**询问自己:用户想要整个 trace 还是一个片段?
- “关注 X / 在 X 之后 / 在 X 与 Y 之间 / 在 X 期间” → 首先解析到一个时间窗口(见步骤 2)。
- 没有范围提示 → 分析整个 trace。
- **解析时间窗口(仅在用户界定了范围时)。**解析器提供了两种发现模式:
两种模式都接受# 查找标记感兴趣区域开始/结束的日志: python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <路径> \ --list-logs --log-message-contains "loaded feed" --log-limit 5 # 或列出 os_signpost 区间(配对的开始/结束),可按名称过滤: python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <路径> \ --list-signposts --signpost-name-contains "ImageDecode"--window START_MS:END_MS来限定发现范围。选择与用户描述匹配的time_ms(对于日志)或start_ms/end_ms(对于 signpost)。构建如--window 10400:11700的时间窗口。 - 运行主要分析(带或不带
--window):python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <路径> \ --json-only --top 10 [--window START_MS:END_MS] - 结合
references/trace-analysis.md进行解读 — 关键诊断项:- 每个相关性中的
main_running_coverage_pct(<25% = 被阻塞;≥75% = CPU 密集型)。 swiftui-causes.top_sources揭示了为什么更新持续发生 — 像UserDefaultObserver.send()或宽EnvironmentWriter条目这样的高边数源是结构性失效错误。修复其中一个通常能消除许多下游的热视图。
- 每个相关性中的
- **当某个特定视图显示为开销大时,询问是谁使其失效。**使用
--fanin-for "<视图名称>"获取驱动更新的源节点的排序列表。 - **可选地关联源代码。**如果用户指向了一个文件,阅读该文件并将视图名称/用户代码符号与其中的标识符匹配。如果没有,根据 SwiftUI 报告的视图名称推荐应打开哪些文件。
- **返回一个优先级排序的计划。**引用证据(覆盖率百分比、热符号、重叠视图、日志时间戳、因果图边)并将每个建议路由到主题路由器参考。
- 仅当用户要求修改时才编辑代码。
主题路由器
针对当前任务相关的每个主题查阅对应的参考文件:
| 主题 | 参考文件 |
|---|---|
| 状态管理 | references/state-management.md |
环境和 @Entry,包括“在 '@Entry var' 中存储闭包/类类型”的警告 | references/environment-patterns.md |
| 视图组合 | references/view-structure.md |
| 视图修饰符和标识 | references/modifier-patterns.md |
| 性能 | references/performance-patterns.md |
| 列表和 ForEach | references/list-patterns.md |
| 可调整大小布局、安全区域、两栏重排、可折叠网格、排列和保留区域 | references/layout-best-practices.md |
| iPhone Duo、可折叠或大屏(先阅读以选择技术) | references/iphone-duo.md |
表单、导航、大屏上的 NavigationSplitView 以及标签栏/侧边栏(sidebarAdaptable) | references/sheet-navigation-patterns.md |
| ScrollView、滚动位置和滚动几何 | references/scroll-patterns.md |
| 焦点管理 | references/focus-patterns.md |
| 动画(基础) | references/animation-basics.md |
| 动画(过渡) | references/animation-transitions.md |
| 动画(高级) | references/animation-advanced.md |
| 无障碍 | references/accessibility-patterns.md |
| Swift Charts | references/charts.md |
| Charts 无障碍 | references/charts-accessibility.md |
| 图像优化和显示缩放 | references/image-optimization.md |
| 工具栏 | references/toolbar-patterns.md |
| 基于文档的应用 | references/document-apps.md |
| WebKit | references/webkit-integration.md |
| 富文本编辑 | references/styled-text-editing.md |
| Liquid Glass (iOS 26+) | references/liquid-glass.md |
| macOS 场景 | references/macos-scenes.md |
| macOS 窗口样式 | references/macos-window-styling.md |
| macOS 视图 | references/macos-views.md |
| 文本模式 | references/text-patterns.md |
| 本地化 | references/localization.md |
| 已弃用 API 查询 | references/latest-apis.md |
| 处理软弃用 API | references/soft-deprecation.md |
| 预览 | references/previews.md |
| Instruments trace 分析 | references/trace-analysis.md |
| Instruments trace 录制 | references/trace-recording.md |
正确性检查清单
以下是硬性规则 — 违反即表示错误:
-
@State属性为private -
@Binding仅在子视图修改父视图状态时使用 - 父视图拥有的输入不存储为
@State/@StateObject;有意的状态初始值需记录为一次性 -
@StateObject用于视图拥有的对象;@ObservedObject用于注入的对象 - iOS 17+:
@State搭配@Observable;@Bindable用于需要绑定的可观察注入对象 -
ForEach使用稳定的标识(绝不使用.indices/\.offset;id 的生命周期超过视图,且不基于可变内容派生) - 每个
ForEach元素的视图数量恒定;List行是单元的 - 自定义
@Environment/@FocusedValue键中不存储闭包 - 自定义
@Entry的默认值是稳定的(不包含Model()/Date()/UUID()表达式) - SwiftUI 显示缩放来自
@Environment(\.displayScale),而非全局屏幕状态 - 安全区域内容不重复应用
GeometryProxy.safeAreaInsets -
.animation(_:value:)始终包含value参数 -
@FocusState属性为private - 在
.focusable()视图的点击手势处理器中没有冗余的@FocusState写入 - 版本特定 API 使用
#available门控并具有合理的回退方案 - 使用图表类型的文件中包含
import Charts - 预览使用自包含的模拟数据;不依赖实时服务或网络