Logo for tanaschita.com

The difference between @StateObject and @ObservedObject in SwiftUI

Learn how to correctly use the property wrappers StateObject and ObservedObject.

31 Jul 2023 · 4 min read

When it comes to state management in SwiftUI combined with reference types, SwiftUI provides two property wrappers: @StateObject and @ObservedObject. Understanding the difference between them is crucial for building robust SwiftUI applications, as it determines how data is managed and flows through the view hierarchy.

Note: Apple introduced the Observation framework at WWDC23 which will make these two property wrappers obsolete in the future. The knowledge around them is still useful since they are used in many existing applications. The knowledge might also help migrate to new Observation framework.

So let's directly dive in and look at an example.

Sponsorship logo
Preparing for a technical iOS job interview
Check out my new book on preparing for a technical iOS job interview with over 200 questions & answers. Test your knowledge on iOS topics such as Swift & Objective-C, SwiftUI & UIKit, Combine, HTTP Networking, Authentication, Core Data, Concurrency with async/await, Security, Automated Testing and more.
LEARN MORE

Let's look at the following example of a view and a view model working together:

struct RandomNameGeneratorView: View {
@ObservedObject private var viewModel = RandomNameGeneratorViewModel()
var body: some View {
VStack {
Text(viewModel.generatedName ?? "Tap the button to generate a new name")
Button("Generate") {
viewModel.generateNewName()
}
}
}
}
class RandomNameGeneratorViewModel: ObservableObject {
@Published var generatedName: String?
func generateNewName() {
generatedName = ...
}
}

The example above shows a view which the user can use to generate a new name every time they tap the generate button. The view references the view model with the @ObservedObject property wrapper so the view is automatically updated when the view model's published properties change.

When using the view, for example as follows:

struct ContentView: View {
var body: some View {
RandomNameGeneratorView()
}
}

everything seems to work fine.

But there is actually a potential error we introduced. As soon as our view hierarchy becomes more complex, we might run into the problem, that a generated name suddenly becomes empty without us resetting it explicitly. The reason behind this behaviour is that we used @ObservedObject to subscribe to model changes.

An @ObservedObject is reinitialized every time their containing view redraws. Since SwiftUI might recreate a view at any time, using @ObservedObject in our example might lead to unwanted behaviour and some headache trying to find the cause.

The correct approach in this case is to use the @StateObject property wrapper instead. @StateObject makes sure the view model retains state between view redraws so we don't lose any state.

An @ObservedObject should only be used to pass a @StateObject into a subview. For example:

struct ContentView: View {
@StateObject private var viewModel = RandomNameGeneratorViewModel()
var body: some View {
RandomNameGeneratorView(viewModel: viewModel)
}
}
struct RandomNameGeneratorView: View {
@ObservedObject var viewModel: RandomNameGeneratorViewModel
...
}

In the example above, we create a two-way binding by passing in a @StateObject and referencing it as an @ObservedObject. This way, every change to published properties of the view model made by any of the view will also be reflected in the other view.

Sponsorship logo
Preparing for a technical iOS job interview
Check out my new book on preparing for a technical iOS job interview with over 200 questions & answers. Test your knowledge on iOS topics such as Swift & Objective-C, SwiftUI & UIKit, Combine, HTTP Networking, Authentication, Core Data, Concurrency with async/await, Security, Automated Testing and more.
LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

observation

swiftui

property wrappers

swift

ios

Migrating to the Observation framework in SwiftUI

Learn how to use SwiftUI's @Observable macro.

07 Aug 2023 · 5 min read

Latest articles and tips

© 2023 tanaschita.com

Privacy policy

Impressum