View identity: if/else vs a modifier

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

Predict the output

CounterView keeps its own @State count. Tap it to 5, then turn Highlight on. What does it show?

struct Screen: View {
    @State private var isHighlighted = false
    var body: some View {
        VStack {
            if isHighlighted {
                CounterView().border(.yellow)
            } else {
                CounterView()
            }
            Toggle("Highlight", isOn: $isHighlighted)
        }
    }
}
Options
Hint 1 of 1

Are the two CounterViews the same view to SwiftUI?

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

Show answer

Answer: B 0, with a yellow border

Correct. The other branch is a different view identity, so its state starts fresh.

Why not the others?
  • A 5, with a yellow border. That needs one view whose border changes, for example .border(isHighlighted ? .yellow : .clear).
  • C 5, without a border. The highlight branch draws the border.
  • D It crashes. Switching branches is legal; it just resets state.

30-second answer

SwiftUI keeps state per view identity. Identity comes from the view's position in the hierarchy (structural identity) or an explicit .id() or ForEach id. An if/else makes two different branches, so switching branches destroys one view, with its state, and creates the other. Prefer changing a modifier's value when it is really the same view.

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

Explain SwiftUI view identity.

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

  • State lives per identity
  • Structural vs explicit identity
  • if/else branches reset state
  • Use modifiers or .id deliberately

Deep dive

ForEach needs stable ids; using indices or UUID() per render breaks animations and state.

.id(value) is a deliberate reset: a new value creates a new identity.

Conditional modifier helpers (.if(condition)) create branches and the same reset bugs.

Identity also drives transitions: insert and remove animations happen when identity changes.

Common mistakes

  • Writing an .if view extension.
  • Generating UUID() ids inside body.
  • Using array indices as ids in editable lists.

Senior take & follow-ups

Seniors explain structural versus explicit identity and why the .if extension is an anti-pattern.

Follow-up questions

Think of your answer first, then open the hint.

  1. How do you reset a form after saving?

    Show hint

    Change its .id().

  2. Why does ForEach(items, id: \.self) misbehave with duplicate values?

    Show hint

    Duplicates share an identity.

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