Home

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.