name: swiftui-performance-developer description: 通过代码审查和Instruments指导审计和提升SwiftUI运行时性能。用于诊断SwiftUI应用中的慢渲染、卡顿滚动、过度视图更新或布局抖动。
SwiftUI性能开发专家(智能路由器)
目的
通过代码审查审计SwiftUI视图性能,并在需要时提供Instruments性能分析的指导。
何时自动激活
- 诊断慢渲染、卡顿滚动、高CPU/内存使用
- 过度视图更新或布局抖动
- 关键词:性能、慢、卡顿、延迟、卡顿、CPU、内存、更新
工作流决策树
- 提供代码 -> 开始代码优先审查
- 仅描述症状 -> 询问代码/上下文,然后进行代码优先审查
- 代码审查无结论 -> 指导用户使用Instruments进行性能分析
基本性能洞察(WWDC24)
SwiftUI视图是描述UI状态的值类型(结构体)——它们不是长期存在的对象。将一个视图拆分为多个子视图不会损害性能,因为视图只是声明性描述。
关键洞察:SwiftUI在后台维护一个高效的数据结构。当状态改变时,创建新的视图值,SwiftUI确定实际需要更新的内容。您不需要为了性能而妥协代码组织。
// ✅ 良好 - 拆分为子视图是免费的
var body: some View {
VStack {
HeaderView(title: title) // 单独视图 = 良好
ContentView(items: items) // 单独视图 = 良好
FooterView(action: saveAction) // 单独视图 = 良好
}
}
// SwiftUI只会在其状态改变时更新特定的子视图
代码优先审查焦点
查找这些常见的性能问题:
状态驱动更新(WWDC24)
SwiftUI自动跟踪依赖项。视图在body中读取的任何数据都成为依赖项:
@Observable class PetModel {
var name: String = "" // ← 如果在body中读取,成为依赖项
var hasAward: Bool = false // ← 仅在实际读取时触发更新
}
struct PetRow: View {
let pet: PetModel
var body: some View {
HStack {
Text(pet.name) // 依赖项:name
if pet.hasAward { // 依赖项:hasAward
Image(systemName: "star.fill")
}
}
}
}
// 当pet.hasAward改变时,SwiftUI自动再次调用body
性能好处:只有实际读取更改数据的视图才会被更新。
视图无效化风暴
// 不良 - 广泛状态触发所有视图
@Observable class Model {
var items: [Item] = []
}
// 良好 - 细粒度的每项状态
@Observable class ItemModel {
var isFavorite: Bool
}
列表中不稳定的身份
// 不良 - id变更导致完全重新渲染
ForEach(items, id: \.self) { item in Row(item) }
// 良好 - 稳定身份
ForEach(items, id: \.id) { item in Row(item) }
body中的繁重工作
// 不良 - 每次渲染分配
var body: some View {
let formatter = NumberFormatter() // 慢
Text(formatter.string(from: value))
}
// 良好 - 缓存的格式化器
static let formatter = NumberFormatter()
var body: some View {
Text(Self.formatter.string(from: value))
}
ForEach中的排序/过滤
// 不良 - 每次body评估重新排序
ForEach(items.sorted(by: sortRule)) { Row($0) }
// 良好 - 预排序的集合
let sortedItems = items.sorted(by: sortRule)
ForEach(sortedItems) { Row($0) }
大图像未经降采样
// 不良 - 在主线程解码全分辨率
Image(uiImage: UIImage(data: data)!)
// 良好 - 先降采样到非主线程
常见代码异味
| 模式 | 问题 | 修复 |
|---|---|---|
NumberFormatter() 在body中 |
每次渲染分配 | 静态缓存的格式化器 |
.filter { } 在ForEach中 |
每次渲染重新计算 | 预过滤,缓存结果 |
id: \.self 在不稳定值上 |
身份变更 | 使用稳定的ID属性 |
UUID() 每次渲染 |
每次新身份 | 将ID存储在模型中 |
GeometryReader 深入树中 |
布局抖动 | 向上移动或使用固定大小 |
if condition { View } 在ForEach中 |
变量视图数量强制完整构建 | 使用opacity(0)或预过滤 |
AnyView 在列表行中 |
隐藏身份和视图数量 | 使用@ViewBuilder或具体类型 |
Instruments性能分析指导
当代码审查无结论时,指导用户进行性能分析:
- 记录:产品 > 配置文件,SwiftUI模板(发布构建)
- 重现:精确交互(滚动、导航、动画)
- 捕获:SwiftUI时间线和时间分析器
- 分析:
- “长视图体更新”(橙色 >500微秒,红色 >1000微秒)
- “卡顿”车道用于帧缺失
- 时间分析器调用树用于热门帧
询问用户:
- 跟踪导出或截图
- 设备/操作系统/构建配置
修复清单
- [ ] 缩小状态范围(
@State/@Observable更接近叶子视图) - [ ] 为
ForEach和列表稳定身份 - [ ] 将繁重工作移出
body(预计算、缓存、@State) - [ ] 为昂贵子树使用
equatable() - [ ] 在渲染前降采样图像
- [ ] 减少布局复杂性或使用固定大小
参考资料
对于详细的WWDC指导:
references/demystify-swiftui-performance-wwdc23.mdreferences/optimizing-swiftui-performance-instruments.mdreferences/understanding-improving-swiftui-performance.md
相关技能
- ios-dev-guidelines -> 通用Swift/iOS模式
- swiftui-patterns-developer -> 视图结构和组合
导航:此技能提供SwiftUI性能审计模式。对于通用iOS开发,参见ios-dev-guidelines。
归因:模式改编自Dimillian/Skills仓库。WWDC24洞察来自“SwiftUI Essentials”会议。