Instruction

State & Observable

In a SwiftUI app, every data value or object that can change needs a single source of truth and a mechanism to enable views to change or observe it. Property wrappers like @State and @Observable enable you to declare how each view interacts with mutable data.

A @State property is a source of truth. In the Observation framework, @State properties can be value types or reference types.

A view that owns a value-type @State property can pass either its value or its binding to its subviews. If it passes a binding to a subview, that subview now has a reference to the source of truth. This allows the subview to update that property’s value or redraw itself when that value changes.

A view that owns a reference-type @State property can pass the object to its subviews, which can pass it on to their subviews. Views can track changes to a reference-type @State object if its class conforms to the Observable protocol. Any change that a view can read from the object causes the view to redraw itself.

Pre-iOS 17

Before iOS 17, @State and @Binding could only be used with value properties, and you’d use @StateObject and @ObservedObject for class objects. To make a class object observable, you’d declare it like this:

class MyViewModelClass: ObservableObject {
  @Published var modelArray: [MyModel] = []
}

MyViewModelClass conforms to ObservableObject and publishes modelArray. A view that instantiated MyViewModelClass as a @StateObject or received it as an @ObservedObject from a parent view would react to changes to modelArray by redrawing itself.

Using iOS 17 Observation Framework

An iOS 17 or later app can adopt the Observation framework. Observation:

  • Lets you track optionals and collections of objects.
  • Updates a view based only on observable properties that the view’s body reads.

Differences from a pre-iOS-17 app are:

  • When you define an observable class, instead of conforming to ObservableObject, attach the Observable() macro @Observable to the type declaration.
  • Don’t mark observable properties as @Published. Instead, hide properties that you don’t want views to observe. You’ll try this out in the second demo video.
  • In views, use @State for both values and objects.
  • When you pass an observable object to a subview, don’t declare it with any property wrapper if the subview reads the object directly. That is if the subview needs only one-way binding. In the next lesson, you’ll use @Bindable to support two-way binding.

Follow along with the demo video to see this in action.

See forum comments
Download course materials from Github
Previous: Introduction Next: Demo 1