SwiftUI and State management: @StateObject, @ObservedObject and @EnvironmentObject

Feb 12, 2023

So what if we want to bind our view with a class object ? We can use @StateObject, @ObservedObject, or @EnvironmentObject to manage the state, but we need our class to conform to the ObservableObject protocol.
As the documentation said : A type of object with a publisher that emits before the object has changed.

That simply mean that our class, acts as a publisher and notifies its subscribers about changes for the properties marked with @Published.

The class if conforming to ObservableObject, let’s mark a property as @Published and connect it to a view.

@StateObject

When using @StateObject, SwiftUI will create the object once. Even if the entire view need to be re-rendered.

In the code above, when the user press the Button, all elements change their color. The Counter object is created once, and keep it's value no matter how many time the color is changed (re-rendered). When our view is the owner of the object (aka it creates it), we need to use @StateObject.

@ObservedObject

On the contrary, when instantiating an @ObservedObject, the object will be re-rendered every time the view is re-rendered.

We can see that the Counter is reset to 0 on every tap, because ContentView does not own StateStepper or Counter, it does not know their state, so they are re-rendered.

@EnvironmentObject

Sometimes, we will have data that not need to be shared with all of the views in our app, think of user’s name or avatar.
So to avoid the tight coupling between views, Apple provide the @EnvironmentObject wrapper.

In the code above, we share to UserProfileScreen view, the name of the user by using the @EnvironmentObject and the modifier .environmentObject, without polluting SettingsScreen view with a dependency it does not need.
Even if @EnvironmentObject is a powerful tool, there is a problem if we are not careful : SwiftUI does not know if the injected object is instantiated, that mean, if our object is nil, the app will crash at runtime.