SwiftUI Dive: `@StateObject` vs `@ObservedObject` — When and Why to Use Each


Introduction
In SwiftUI, managing the state of your data is a foundational skill. While @StateObject
and @ObservedObject
are both used to work with observable reference types, they serve very different purposes. Misusing them can lead to unexpected behaviors like duplicated initializations or loss of state during view redraws.
In this article, we’ll demystify @StateObject
and @ObservedObject
with clear examples, highlight when to use each, and explain their lifecycle differences—a topic that often trips up even experienced developers.
What is an ObservableObject
?
To understand @StateObject
and @ObservedObject
, we first need to look at ObservableObject
. It’s a protocol that allows reference types (usually class
-based view models) to notify SwiftUI when data changes using @Published
properties.
class CounterViewModel: ObservableObject {
@Published var count = 0
}
This pattern is core to MVVM in SwiftUI, where the view observes a view model and automatically updates the UI when properties change.
@StateObject
: Long-Lived and View-Owned
Use @StateObject
when the view creates and owns the instance of an observable object. This tells SwiftUI to instantiate and retain the object only once—even if the view redraws due to state changes or layout updates.
✅ Important: @StateObject
ensures the object is not reinitialized when the view is re-rendered.
Example:
struct CounterView: View {
@StateObject private var viewModel = CounterViewModel()
var body: some View {
VStack {
Text("Count: \(viewModel.count)")
Button("Increment") {
viewModel.count += 1
}
}
}
}
Even if CounterView
is reloaded (e.g., due to a navigation pop/push or another state change), viewModel
retains its current state — count doesn’t reset.
@ObservedObject
: For Injected Dependencies
Use @ObservedObject
when the view receives an already-created observable object — typically from a parent view. SwiftUI doesn’t own this object, so it will reinitialize it if the parent re-renders and creates a new instance during the redraw.
⚠️ Caution: If the object is initialised inline inside the view using @ObservedObject
, it will be recreated every time the view updates — which means you’ll lose state.
Example:
struct CounterRowView: View {
@ObservedObject var viewModel: CounterViewModel
var body: some View {
Text("Count: \(viewModel.count)")
}
}
Here, CounterRowView
does not own the view model. It observes the data passed in from its parent — that’s the key difference.
Key Behavioural Difference: Initialization and Lifecycle
Let’s highlight the critical distinction between the two:
✅
@StateObject
is initialized once and remains alive as long as the view is alive, even if the view re-renders.❌
@ObservedObject
does not manage the lifecycle — if the object is created in the body or initializer and not retained elsewhere, it will be reinitialized every time the view updates.
Misuse Example — What Not to Do:
struct FaultyView: View {
@ObservedObject var viewModel = CounterViewModel() // ❌ Recreated on every redraw
var body: some View {
Text("Count: \(viewModel.count)")
}
}
This is incorrect usage. Every time SwiftUI redraws this view, a new view model is created, and the count
resets. To fix this, you should use @StateObject
.
When Should You Use Each?
✅ Use
@StateObject
when:The view creates the observable object.
The view is responsible for managing the object's lifecycle.
You want the object to be initialized only once, even when the view redraws.
You need the object to retain its state across view reloads.
🔄 Use
@ObservedObject
when:The observable object is passed from a parent view or an external source.
The view should observe the object but not manage its lifecycle.
You don't need to persist state across redraws (e.g., for lightweight or shared models).
⚠️ Tip:
Misusing these wrappers—like using @ObservedObject
to create a new object in the view—can cause unexpected behavior, including loss of state or unnecessary re-initializations.
Conclusion
Correctly using @StateObject
and @ObservedObject
is crucial for building reliable SwiftUI applications. Here’s the mental model:
Use
@StateObject
when the view owns the data and should manage its lifecycle.Use
@ObservedObject
when the view depends on external data passed from a parent.
And remember: if your observable object is being reinitialized unexpectedly, double-check whether you're using @StateObject
when you should be.
Lastly, if you have feedback, suggestions, or notice anything that needs correcting, please don’t hesitate to let me know — I’d love to hear your thoughts!
Subscribe to my newsletter
Read articles from Ghoshit Vora directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Ghoshit Vora
Ghoshit Vora
Senior iOS Developer with a strong background in building scalable and maintainable mobile applications using Swift, SwiftUI, and UIKit. Skilled in architecture patterns like MVVM, Clean Architecture, and Protocol-Oriented Programming. I focus on writing clean, testable code, implementing responsive UI, and optimizing app performance while following SOLID principles and leveraging Combine, Swift Concurrency, and Core Data in modern iOS development.