State and data flow
Who owns the value, and who may change it
Every property wrapper in SwiftUI answers one question: who owns this value, and who is allowed to change it? Choosing the wrong one rarely produces a compile error. It produces a view that does not update, or one that updates far too often, or state that resets when nobody asked it to.
| Wrapper | Owner | Use for |
|---|---|---|
@State |
this view | value-type state this view alone owns |
@Binding |
someone else | a two-way handle passed down |
@Observable / @Bindable |
a reference type | model objects shared across views |
@Environment |
the environment | values handed down implicitly |
The three chapters here take that table apart.
Who owns the value is the decision procedure — @State against @Binding against a model
object — and the specific symptom each wrong answer produces, so you can read a bug backwards to
the mistake.
Observation is what @Observable actually does: how SwiftUI knows which properties a view read,
and why that made ObservableObject and @Published obsolete rather than merely more verbose.
The environment is dependency injection down the view tree — what belongs in it, what very much does not, and how to add a key of your own.
One rule worth carrying into all three: state belongs at the lowest view that needs it, and no lower. Too high, and unrelated views redraw for changes that do not concern them. Too low, and you cannot share it, so you end up threading bindings through five layers of views that do not care.