Audit and improve SwiftUI runtime performance. Use for requests to diagnose slow rendering, janky scrolling, high CPU/memory usage, excessive view updates, or layout thrash in SwiftUI apps.
From ios-swift-skillsnpx claudepluginhub patrickserrano/skillsThis skill uses the workspace's default tool permissions.
Audit SwiftUI view performance from instrumentation and baselining to root-cause analysis and concrete remediation steps.
id churn, UUID() per render)body (formatting, sorting, image decoding)GeometryReader, preference chains)If code review is inconclusive, explain how to collect data:
Ask for:
bodyBad:
var body: some View {
let formatter = NumberFormatter() // Slow allocation every render
Text(formatter.string(from: value))
}
Good:
final class Formatters {
static let number = NumberFormatter()
}
var body: some View {
Text(Formatters.number.string(from: value))
}
Bad:
var filtered: [Item] {
items.filter { $0.isEnabled } // Runs every body eval
}
Good:
@State private var filtered: [Item] = []
.onChange(of: items) {
filtered = items.filter { $0.isEnabled }
}
Bad:
ForEach(items.sorted(by: sortRule)) { item in
Row(item)
}
Good:
let sortedItems = items.sorted(by: sortRule) // Compute once
ForEach(sortedItems) { item in
Row(item)
}
Bad:
ForEach(items, id: \.self) { item in // \.self may not be stable
Row(item)
}
Good:
ForEach(items, id: \.stableID) { item in
Row(item)
}
Bad:
Image(uiImage: UIImage(data: data)!)
Good:
// Decode/downsample off main thread, cache the result
@State private var image: UIImage?
.task {
image = await ImageLoader.load(data: data, targetSize: size)
}
Bad:
@Observable class Model {
var items: [Item] = []
}
var body: some View {
Row(isFavorite: model.items.contains(item)) // Entire array dependency
}
Good:
// Granular view models or per-item state to reduce update fan-out
| Issue | Fix |
|---|---|
| Broad state changes | Narrow scope with @State/@Observable closer to leaves |
| Unstable identities | Use stable, unique IDs for ForEach |
| Heavy work in body | Precompute, cache, move to @State |
| Expensive subtrees | Use equatable() or value wrappers |
| Large images | Downsample before rendering |
| Layout complexity | Reduce nesting, use fixed sizing where possible |
Ask user to re-run same capture and compare with baseline:
Provide:
# Build for profiling
xcodebuild -scheme MyApp -configuration Release -destination 'platform=iOS Simulator,name=iPhone 15 Pro' build
# Open in Instruments
open -a Instruments