8.10 · State, bindings, Observation and environment, checked by running them

Most SwiftUI state bugs come from not knowing when an initialiser runs, what a tracking scope really saw, or what a binding is. Each of these was run: in an iOS Simulator through UIHostingController, or as a plain program where no rendering is needed.

Mental model. A view struct is a throw-away description; its state lives in the graph. Ask three things of any value: who owns it, who read it during body, and what notifies when it changes.

Where state lives

When initialisers run, and how a binding is just a getter and a setter.

  1. A view’s init runs on every parent update. When does the initial value of @State or @StateObject actually get created? 8.10.1 · L3
    The view struct is rebuilt every time a parent’s body runs, so its init runs again and again. The check counts it: after the first render and three parent…
  2. What is a Binding really, and how do derived, constant and transforming bindings behave? 8.10.2 · L2
    A Binding stores no value: it is a getter and a setter (plus a transaction). $state hands you one that reads and writes the state’s storage; Binding(get:set:)…

What gets tracked

Observation granularity, the older ObservableObject, environment and stored preferences.

  1. What exactly does Observation track: computed properties, ignored properties, collections, nested objects and equal writes? 8.10.3 · L3
    withObservationTracking (what SwiftUI wraps around body) records every property read during the tracking closure and fires once when any of them changes. The…
  2. When exactly does ObservableObject publish, and why do nested objects and equal assignments surprise people? 8.10.4 · L3
    @Published sends objectWillChange before the new value is stored. In the check the sink runs while title is still t, and the $title publisher likewise delivers…
  3. If a parent changes one environment value, which child views re-run their body? 8.10.5 · L3
    The environment is tracked per key. In the check the parent sets a custom level value (declared with the @Entry macro) around three children. When level…
  4. How does @AppStorage behave: where is the value, what happens when it is removed or changed elsewhere, and what can you store? 8.10.6 · L2
    @AppStorage("key") var n = 3 reads and writes UserDefaults (the standard suite unless you pass store:). The declared value is only a default: it is not written…

More in SwiftUI