The SwiftUI Guide to Clean State Management and Dependency Injection


Why Use @StateObject
in the App File?
In SwiftUI, you use @StateObject
when you want to create and manage a view model that your whole app will use.
What is @StateObject
?
@StateObject
is how you create and keep a view model (or any observable class) in SwiftUI.
SwiftUI will watch it for changes, and automatically update the UI when something inside it changes.
It makes sure the view model is only created once and stays alive as long as the app runs.
Example
ViewModel as ObservableObject
SwiftUI watches ObservableObject
for changes and updates the view.
import SwiftUI
import Combine
class MyViewModel: ObservableObject {
@Published var counter: Int = 0
func increment() {
counter += 1
}
}
with @StateObject SwiftUI will watch it for changes, and automatically update the UI
Don't pass state — inject it with .environmentObject()"
@main
struct MyApp: App {
@StateObject private var viewModel = MyViewModel()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(viewModel) // Inject into environment
}
}
}
All views using @EnvironmentObject
automatically access the same shared data injected in the App file.
struct ContentView: View {
@EnvironmentObject var viewModel: MyViewModel
var body: some View {
VStack {
Text("Counter: \(viewModel.counter)")
Button("Increment") {
viewModel.increment()
}
}
}
}
@ObservedObject Vs @StateObject
Passing State with @ObservedObject
You manually pass the view model to each view that needs it:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
// Manually create and pass the view model
ContentView(viewModel: MyViewModel())
}
}
}
struct ContentView: View {
@ObservedObject var viewModel: MyViewModel
var body: some View {
Text("Count: \(viewModel.counter)")
}
}
By @ObservedObject
, the App file creates the view model and passes it directly to ContentView
.
By @EnvironmentObject
, the App file injects the view model into the environment, and ContentView
accesses it automatically.
Don’t pass state – inject it with .environmentObject()
— own it, share it, and keep your SwiftUI clean.
Subscribe to my newsletter
Read articles from Tabassum Akter Nusrat directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Tabassum Akter Nusrat
Tabassum Akter Nusrat
Former Android dev at Samsung R&D, now diving deep into iOS development. Writing daily about Swift Concurrency, SwiftUI, and the journey of building real-world apps. Passionate about clean architecture, mental health tech, and learning in public.