swiftui-performance-audit by dimillian/skills
npx skills add https://github.com/dimillian/skills --skill swiftui-performance-audit对 SwiftUI 视图性能进行端到端审计,从性能检测和基线建立,到根因分析和具体的修复步骤。
收集:
重点关注:
id 频繁变动,每次渲染都使用 UUID())。if/else 返回不同的根分支)。body 中的繁重工作(格式化、排序、图像解码)。GeometryReader、偏好链)。提供:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
解释如何使用 Instruments 收集数据:
要求提供:
优先排查可能的 SwiftUI 问题根源:
id 频繁变动,每次渲染都使用 UUID())。if/else 返回不同的根分支)。body 中的繁重工作(格式化、排序、图像解码)。GeometryReader、偏好链)。根据跟踪文件/日志中的证据总结发现。
应用针对性修复:
@State/@Observable 移近叶子视图)。ForEach 和列表稳定标识符。body(预计算、缓存、使用 @State)。equatable() 或值包装器。在代码审查时留意这些模式。
body 中开销大的格式化器var body: some View {
let number = NumberFormatter() // 缓慢的分配
let measure = MeasurementFormatter() // 缓慢的分配
Text(measure.string(from: .init(value: meters, unit: .meters)))
}
推荐在模型或专用辅助类中使用缓存的格式化器:
final class DistanceFormatter {
static let shared = DistanceFormatter()
let number = NumberFormatter()
let measure = MeasurementFormatter()
}
var filtered: [Item] {
items.filter { $0.isEnabled } // 每次 body 求值时都会运行
}
推荐在变更时进行预计算或缓存:
@State private var filtered: [Item] = []
// 当输入改变时更新 filtered
body 或 ForEach 中进行排序/过滤List {
ForEach(items.sorted(by: sortRule)) { item in
Row(item)
}
}
推荐在视图更新前排序一次:
let sortedItems = items.sorted(by: sortRule)
ForEach 中进行内联过滤ForEach(items.filter { $0.isEnabled }) { item in
Row(item)
}
推荐使用具有稳定标识符的预过滤集合。
ForEach(items, id: \.self) { item in
Row(item)
}
避免对非稳定值使用 id: \.self;应使用稳定的 ID。
var content: some View {
if isEditing {
editingView
} else {
readOnlyView
}
}
推荐使用一个稳定的基础视图,并将条件局部化到特定区域或修饰符(例如在 toolbar、行内容、overlay 或 disabled 内部)。这可以减少根标识符的变动,有助于 SwiftUI 的差异比较保持高效。
Image(uiImage: UIImage(data: data)!)
推荐在主线程外进行解码/降采样并存储结果。
@Observable class Model {
var items: [Item] = []
}
var body: some View {
Row(isFavorite: model.items.contains(item))
}
推荐使用粒度更细的视图模型或每个项目的状态,以减少更新传播范围。
请用户重新运行相同的性能捕获,并与基线指标进行比较。如果提供了数据,则总结差异(CPU、掉帧、内存峰值)。
提供:
根据用户提供的信息,在 references/ 下添加 Apple 文档和 WWDC 资源。
references/optimizing-swiftui-performance-instruments.mdreferences/understanding-improving-swiftui-performance.mdreferences/understanding-hangs-in-your-app.mdreferences/demystify-swiftui-performance-wwdc23.md每周安装量
2.4K
代码仓库
GitHub 星标数
2.0K
首次出现
2026年1月20日
安全审计
安装于
codex1.9K
opencode1.9K
gemini-cli1.9K
github-copilot1.8K
claude-code1.7K
amp1.6K
Audit SwiftUI view performance end-to-end, from instrumentation and baselining to root-cause analysis and concrete remediation steps.
Collect:
Focus on:
id churn, UUID() per render).if/else returning different root branches).body (formatting, sorting, image decoding).GeometryReader, preference chains).Provide:
Explain how to collect data with Instruments:
Ask for:
Prioritize likely SwiftUI culprits:
id churn, UUID() per render).if/else returning different root branches).body (formatting, sorting, image decoding).GeometryReader, preference chains).Summarize findings with evidence from traces/logs.
Apply targeted fixes:
@State/@Observable closer to leaf views).ForEach and lists.body (precompute, cache, @State).equatable() or value wrappers for expensive subtrees.Look for these patterns during code review.
bodyvar body: some View {
let number = NumberFormatter() // slow allocation
let measure = MeasurementFormatter() // slow allocation
Text(measure.string(from: .init(value: meters, unit: .meters)))
}
Prefer cached formatters in a model or a dedicated helper:
final class DistanceFormatter {
static let shared = DistanceFormatter()
let number = NumberFormatter()
let measure = MeasurementFormatter()
}
var filtered: [Item] {
items.filter { $0.isEnabled } // runs on every body eval
}
Prefer precompute or cache on change:
@State private var filtered: [Item] = []
// update filtered when inputs change
body or ForEachList {
ForEach(items.sorted(by: sortRule)) { item in
Row(item)
}
}
Prefer sort once before view updates:
let sortedItems = items.sorted(by: sortRule)
ForEachForEach(items.filter { $0.isEnabled }) { item in
Row(item)
}
Prefer a prefiltered collection with stable identity.
ForEach(items, id: \.self) { item in
Row(item)
}
Avoid id: \.self for non-stable values; use a stable ID.
var content: some View {
if isEditing {
editingView
} else {
readOnlyView
}
}
Prefer one stable base view and localize conditions to sections/modifiers (for example inside toolbar, row content, overlay, or disabled). This reduces root identity churn and helps SwiftUI diffing stay efficient.
Image(uiImage: UIImage(data: data)!)
Prefer decode/downsample off the main thread and store the result.
@Observable class Model {
var items: [Item] = []
}
var body: some View {
Row(isFavorite: model.items.contains(item))
}
Prefer granular view models or per-item state to reduce update fan-out.
Ask the user to re-run the same capture and compare with baseline metrics. Summarize the delta (CPU, frame drops, memory peak) if provided.
Provide:
Add Apple documentation and WWDC resources under references/ as they are supplied by the user.
references/optimizing-swiftui-performance-instruments.mdreferences/understanding-improving-swiftui-performance.mdreferences/understanding-hangs-in-your-app.mdreferences/demystify-swiftui-performance-wwdc23.mdWeekly Installs
2.4K
Repository
GitHub Stars
2.0K
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex1.9K
opencode1.9K
gemini-cli1.9K
github-copilot1.8K
claude-code1.7K
amp1.6K
99,500 周安装