How do you debug unexpected SwiftUI re-renders?
1. Understand the two-stage process first
Body re-evaluation (cheap, happens often) vs. actual diffing/re-render (expensive, should be minimal).
2. Make re-renders visible first
var body: some View {
let _ = Self._printChanges()
...
}
Also Instruments’ SwiftUI “View Body” instrument.
3. The most common root causes
a) Observable object exposing too much state to too many views — fixed by splitting objects or adopting @Observable’s field-level tracking.
b) Passing a whole model/object down when only a few fields are used
c) Non-Equatable/unstable identity causing unnecessary diffing work
d) Closures capturing more state than needed
e) @State/@StateObject accidentally reset due to view identity changes
f) @EnvironmentObject/@Environment propagating changes too broadly
4. Techniques to isolate and fix
Extract subviews aggressively; adopt @Observable over ObservableObject; add Equatable conformance and use .equatable().
5. Don’t over-index on body re-evaluation frequency alone
Confirm with Instruments that a pattern is actually costing measurable render time before optimizing.
One-liner if pressed: “I’d start with Self._printChanges() to see exactly which property triggered a given re-evaluation, then check Instruments’ SwiftUI View Body instrument to confirm it’s actually costing real render time. The most common root cause is a broadly-scoped observable object or a whole-object parameter causing views to invalidate on state they don’t even read.”