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
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
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
Preparing for a technical iOS Job Interview with over 300 questions & answers. Covering Swift & Objective-C, SwiftUI & UIKit, Combine, HTTP Networking, iOS File System, Core Data, Concurrency with async/await, Security, Automated Testing, Dependency Management, AI & Machine Learning and more.
LEARN MORE
Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE
Sponsorship logo
Become a sponsor of tanaschita.com
By publishing an article on different iOS topics every week, tanaschita.com is constantly growing in the developer community and may provide a great audience for you as a sponsor.
CLICK TO LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

swiftui

property wrappers

swift

ios

Presenting alerts and confirmation dialogs from identifiable data in SwiftUI

Learn how to present alerts and confirmation dialogs using optional identifiable items instead of Boolean state.

24 Aug 2026 · 4 min read

Latest articles and tips

© 2026 tanaschita.com

Privacy policy

Impressum