中文导读
SwiftUI Performance Audit 是一套面向一人公司的通用 playbook,帮助你用更少的人力完成更稳的增长、交付与决策。
说明: 原始步骤、命令与 API 名称保留英文,以避免参数和接口名称失真。
概览
Attribution: copied from @Dimillian's Dimillian/Skills (2025-12-31).
概览
Audit SwiftUI view performance end-to-end, from instrumentation and baselining to root-cause analysis and concrete remediation steps. Workflow Decision Tree If the user provides code, start with "Code-First Review." If the user only describes symptoms, ask for minimal code/context, then do "Code-First Review." If code review is inconclusive, go to "Guide the User to Profile" and ask for a trace or screenshots.
- Code-First Review
Collect:
- Target view/feature code.
- Data flow: state, environment, observable models.
- Symptoms and reproduction steps.
- Focus on:
- View invalidation storms from broad state changes.
- Unstable identity in lists (id churn, UUID() per render).
- Heavy work in body (formatting, sorting, image decoding).
- Layout thrash (deep stacks, GeometryReader, preference chains).
- Large images without downsampling or resizing.
- Over-animated hierarchies (implicit animations on large trees).
- Provide:
- Likely root causes with code references.
- Suggested fixes and refactors.
- If needed, a minimal repro or instrumentation suggestion.
- Guide the User to Profile
- Explain how to collect data with Instruments:
- Use the SwiftUI template in Instruments (Release build).
- Reproduce the exact interaction (scroll, navigation, animation).
- Capture SwiftUI timeline and Time Profiler.
- Export or screenshot the relevant lanes and the call tree.
- Ask for:
- Trace export or screenshots of SwiftUI lanes + Time Profiler call tree.
- Device/OS/build configuration.
- Analyze and Diagnose
- Prioritize likely SwiftUI culprits:
- View invalidation storms from broad state changes.
- Unstable identity in lists (id churn, UUID() per render).
- Heavy work in body (formatting, sorting, image decoding).
- Layout thrash (deep stacks, GeometryReader, preference chains).
- Large images without downsampling or resizing.
- Over-animated hierarchies (implicit animations on large trees).
- Summarize findings with evidence from traces/logs.
- Remediate
- Apply targeted fixes:
- Narrow state scope (@State/@Observable closer to leaf views).
- Stabilize identities for ForEach and lists.
- Move heavy work out of body (precompute, cache, @State).
- Use equatable() or value wrappers for expensive subtrees.
- Downsample images before rendering.
- Reduce layout complexity or use fixed sizing where possible.
- Common Code Smells (and Fixes)
- Look for these patterns during code review.
- Expensive formatters in body
- var 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()
- }
- Computed properties that do heavy work
- 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
- Sorting/filtering in body or ForEach
- List {
- ForEach(items.sorted(by: sortRule)) { item in
- Row(item)
- }
- }
- Prefer sort once before view updates:
- let sortedItems = items.sorted(by: sortRule)
- Inline filtering in ForEach
- ForEach(items.filter { $0.isEnabled }) { item in
- Row(item)
- }
- Prefer a prefiltered collection with stable identity.
- Unstable identity
- ForEach(items, id: \.self) { item in
- Row(item)
- }
- Avoid id: \.self for non-stable values; use a stable ID.
- Image decoding on the main thread
- Image(uiImage: UIImage(data: data)!)
- Prefer decode/downsample off the main thread and store the result.
- Broad dependencies in observable models
- @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.
- Verify
- Ask the user to re-run the same capture and compare with baseline metrics.
- Summarize the delta (CPU, frame drops, memory peak) if provided.
- Outputs
- Provide:
- A short metrics table (before/after if available).
- Top issues (ordered by impact).
- Proposed fixes with estimated effort.
- References
- Add Apple documentation and WWDC resources under references/ as they are supplied by the user.
- Optimizing SwiftUI performance with Instruments: references/optimizing-swiftui-performance-instruments.md
- Understanding and improving SwiftUI performance: references/understanding-improving-swiftui-performance.md
- Understanding hangs in your app: references/understanding-hangs-in-your-app.md
- Demystify SwiftUI performance (WWDC23): references/demystify-swiftui-performance-wwdc23.md
SKILL.md 原文件
预览原始 SKILL.md. 下面可以直接查看完整原文。可滚动阅读、检查结构,再下载精确的 SKILL.md 原文件。
# swiftui-performance-audit
SwiftUI Performance Audit
Attribution: copied from @Dimillian's Dimillian/Skills (2025-12-31).
Overview
Audit SwiftUI view performance end-to-end, from instrumentation and baselining to root-cause analysis and concrete remediation steps.
Workflow Decision Tree
If the user provides code, start with "Code-First Review."
If the user only describes symptoms, ask for minimal code/context, then do "Code-First Review."
If code review is inconclusive, go to "Guide the User to Profile" and ask for a trace or screenshots.
1. Code-First Review
Collect:
Target view/feature code.
Data flow: state, environment, observable models.
Symptoms and reproduction steps.
Focus on:
View invalidation storms from broad state changes.
Unstable identity in lists (id churn, UUID() per render).
Heavy work in body (formatting, sorting, image decoding).
Layout thrash (deep stacks, GeometryReader, preference chains).
Large images without downsampling or resizing.
Over-animated hierarchies (implicit animations on large trees).
Provide:
Likely root causes with code references.
Suggested fixes and refactors.
If needed, a minimal repro or instrumentation suggestion.
2. Guide the User to Profile
Explain how to collect data with Instruments:
Use the SwiftUI template in Instruments (Release build).
Reproduce the exact interaction (scroll, navigation, animation).
Capture SwiftUI timeline and Time Profiler.
Export or screenshot the relevant lanes and the call tree.
Ask for:
Trace export or screenshots of SwiftUI lanes + Time Profiler call tree.
Device/OS/build configuration.
3. Analyze and Diagnose
Prioritize likely SwiftUI culprits:
View invalidation storms from broad state changes.
Unstable identity in lists (id churn, UUID() per render).
Heavy work in body (formatting, sorting, image decoding).
Layout thrash (deep stacks, GeometryReader, preference chains).
Large images without downsampling or resizing.
Over-animated hierarchies (implicit animations on large trees).
Summarize findings with evidence from traces/logs.
4. Remediate
Apply targeted fixes:
Narrow state scope (@State/@Observable closer to leaf views).
Stabilize identities for ForEach and lists.
Move heavy work out of body (precompute, cache, @State).
Use equatable() or value wrappers for expensive subtrees.
Downsample images before rendering.
Reduce layout complexity or use fixed sizing where possible.
Common Code Smells (and Fixes)
Look for these patterns during code review.
Expensive formatters in body
var 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()
}
Computed properties that do heavy work
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
Sorting/filtering in body or ForEach
List {
ForEach(items.sorted(by: sortRule)) { item in
Row(item)
}
}
Prefer sort once before view updates:
let sortedItems = items.sorted(by: sortRule)
Inline filtering in ForEach
ForEach(items.filter { $0.isEnabled }) { item in
Row(item)
}
Prefer a prefiltered collection with stable identity.
Unstable identity
ForEach(items, id: \.self) { item in
Row(item)
}
Avoid id: \.self for non-stable values; use a stable ID.
Image decoding on the main thread
Image(uiImage: UIImage(data: data)!)
Prefer decode/downsample off the main thread and store the result.
Broad dependencies in observable models
@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.
5. Verify
Ask the user to re-run the same capture and compare with baseline metrics.
Summarize the delta (CPU, frame drops, memory peak) if provided.
Outputs
Provide:
A short metrics table (before/after if available).
Top issues (ordered by impact).
Proposed fixes with estimated effort.
References
Add Apple documentation and WWDC resources under references/ as they are supplied by the user.
Optimizing SwiftUI performance with Instruments: references/optimizing-swiftui-performance-instruments.md
Understanding and improving SwiftUI performance: references/understanding-improving-swiftui-performance.md
Understanding hangs in your app: references/understanding-hangs-in-your-app.md
Demystify SwiftUI performance (WWDC23): references/demystify-swiftui-performance-wwdc23.md
预览原始 SKILL.md. 下面可以直接查看完整原文。可滚动阅读、检查结构,再下载精确的 SKILL.md 原文件。
# swiftui-performance-audit
SwiftUI Performance Audit
Attribution: copied from @Dimillian's Dimillian/Skills (2025-12-31).
Overview
Audit SwiftUI view performance end-to-end, from instrumentation and baselining to root-cause analysis and concrete remediation steps.
Workflow Decision Tree
If the user provides code, start with "Code-First Review."
If the user only describes symptoms, ask for minimal code/context, then do "Code-First Review."
If code review is inconclusive, go to "Guide the User to Profile" and ask for a trace or screenshots.
1. Code-First Review
Collect:
Target view/feature code.
Data flow: state, environment, observable models.
Symptoms and reproduction steps.
Focus on:
View invalidation storms from broad state changes.
Unstable identity in lists (id churn, UUID() per render).
Heavy work in body (formatting, sorting, image decoding).
Layout thrash (deep stacks, GeometryReader, preference chains).
Large images without downsampling or resizing.
Over-animated hierarchies (implicit animations on large trees).
Provide:
Likely root causes with code references.
Suggested fixes and refactors.
If needed, a minimal repro or instrumentation suggestion.
2. Guide the User to Profile
Explain how to collect data with Instruments:
Use the SwiftUI template in Instruments (Release build).
Reproduce the exact interaction (scroll, navigation, animation).
Capture SwiftUI timeline and Time Profiler.
Export or screenshot the relevant lanes and the call tree.
Ask for:
Trace export or screenshots of SwiftUI lanes + Time Profiler call tree.
Device/OS/build configuration.
3. Analyze and Diagnose
Prioritize likely SwiftUI culprits:
View invalidation storms from broad state changes.
Unstable identity in lists (id churn, UUID() per render).
Heavy work in body (formatting, sorting, image decoding).
Layout thrash (deep stacks, GeometryReader, preference chains).
Large images without downsampling or resizing.
Over-animated hierarchies (implicit animations on large trees).
Summarize findings with evidence from traces/logs.
4. Remediate
Apply targeted fixes:
Narrow state scope (@State/@Observable closer to leaf views).
Stabilize identities for ForEach and lists.
Move heavy work out of body (precompute, cache, @State).
Use equatable() or value wrappers for expensive subtrees.
Downsample images before rendering.
Reduce layout complexity or use fixed sizing where possible.
Common Code Smells (and Fixes)
Look for these patterns during code review.
Expensive formatters in body
var 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()
}
Computed properties that do heavy work
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
Sorting/filtering in body or ForEach
List {
ForEach(items.sorted(by: sortRule)) { item in
Row(item)
}
}
Prefer sort once before view updates:
let sortedItems = items.sorted(by: sortRule)
Inline filtering in ForEach
ForEach(items.filter { $0.isEnabled }) { item in
Row(item)
}
Prefer a prefiltered collection with stable identity.
Unstable identity
ForEach(items, id: \.self) { item in
Row(item)
}
Avoid id: \.self for non-stable values; use a stable ID.
Image decoding on the main thread
Image(uiImage: UIImage(data: data)!)
Prefer decode/downsample off the main thread and store the result.
Broad dependencies in observable models
@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.
5. Verify
Ask the user to re-run the same capture and compare with baseline metrics.
Summarize the delta (CPU, frame drops, memory peak) if provided.
Outputs
Provide:
A short metrics table (before/after if available).
Top issues (ordered by impact).
Proposed fixes with estimated effort.
References
Add Apple documentation and WWDC resources under references/ as they are supplied by the user.
Optimizing SwiftUI performance with Instruments: references/optimizing-swiftui-performance-instruments.md
Understanding and improving SwiftUI performance: references/understanding-improving-swiftui-performance.md
Understanding hangs in your app: references/understanding-hangs-in-your-app.md
Demystify SwiftUI performance (WWDC23): references/demystify-swiftui-performance-wwdc23.md
评论与讨论
添加评论