Why body runs often, and keeping it cheap

SwiftUI Mid-level Swift 5.1+ iOS 17+ Reviewed By Alok Singh

Predict the output

After the first render, the user taps Add 3 times. How many more times does 'Footer body' print?

struct Parent: View {
    @State private var count = 0
    var body: some View {
        VStack {
            Text("\(count)")
            Footer()
            Button("Add") { count += 1 }
        }
    }
}
struct Footer: View {
    var body: some View {
        let _ = print("Footer body")
        Text("Footer")
    }
}
Options
Hint 1 of 1

What changed in Footer between renders?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: B 0, because Footer has no inputs that changed

Correct. SwiftUI compares the new Footer value with the old one and skips body when they are equal.

Why not the others?
  • A 3, because the parent's body runs again each time. The parent's body runs, but Footer's inputs didn't change, so SwiftUI skips its body.
  • C 1. There is no extra render; nothing Footer depends on changed.
  • D 6. Each tap causes at most one parent update, and Footer is skipped.

30-second answer

A View is a lightweight description, not the rendered view. SwiftUI calls body whenever something it depends on changes, then diffs the result. Calling body often is normal and cheap if body is cheap. It becomes a problem when body does real work (formatting, sorting, network calls) or depends on state it doesn't need.

Practise saying it · 45 s. No recording, just a timer

Explain why body runs often and when it matters.

Say your answer out loud, then check which of these points you covered:

  • View is a description
  • body runs on dependency change
  • Keep body cheap
  • Measure with _printChanges and Instruments

Deep dive

Child views whose inputs didn't change are usually skipped.

Split big views so state changes invalidate small parts; Observation helps by tracking per property.

Move formatting and filtering into the model, or cache it.

Use Self._printChanges() in debug builds and the SwiftUI instrument in Instruments to see why a body ran.

Common mistakes

  • Doing expensive work or side effects in body.
  • One giant view that reads every piece of state.
  • Creating formatters inside body.

Senior take & follow-ups

Seniors describe how invalidation works and how they measure it, rather than saying 'SwiftUI is slow'.

Follow-up questions

Think of your answer first, then open the hint.

  1. How do you find out why a view re-rendered?

    Show hint

    Self._printChanges() and the SwiftUI template in Instruments.

  2. What does EquatableView do?

    Show hint

    It lets you control when a view counts as changed.

Suggest a fix if something here is wrong or out of date.