How to Use @EnvironmentObject in SwiftUI for Shared Data
Use
@EnvironmentObject in SwiftUI to share a data model across multiple views without passing it explicitly. Declare a shared observable object with ObservableObject, inject it with .environmentObject() on a parent view, and access it in child views using @EnvironmentObject property wrapper.Syntax
The @EnvironmentObject property wrapper lets a SwiftUI view access an observable object shared in the environment. You declare a class conforming to ObservableObject to hold your data. Then you inject it into the view hierarchy using .environmentObject(). Child views read it with @EnvironmentObject without needing to pass it manually.
- ObservableObject: A class that holds data and notifies views when data changes.
- @EnvironmentObject: Property wrapper to access shared data from environment.
- .environmentObject(): Modifier to inject the shared object into the view hierarchy.
swift
class UserSettings: ObservableObject { @Published var username: String = "Guest" } struct ContentView: View { @EnvironmentObject var settings: UserSettings var body: some View { Text("Hello, \(settings.username)!") } } // Inject in parent view ContentView().environmentObject(UserSettings())
Output
Hello, Guest!
Example
This example shows a shared UserSettings object injected at the root. The ContentView and its child ProfileView both access and update the username via @EnvironmentObject. Changes in one view reflect automatically in the other.
swift
import SwiftUI class UserSettings: ObservableObject { @Published var username: String = "Guest" } struct ContentView: View { @EnvironmentObject var settings: UserSettings var body: some View { VStack { Text("Hello, \(settings.username)!") ProfileView() } } } struct ProfileView: View { @EnvironmentObject var settings: UserSettings var body: some View { TextField("Username", text: $settings.username) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() } } @main struct MyApp: App { var settings = UserSettings() var body: some Scene { WindowGroup { ContentView().environmentObject(settings) } } }
Output
UI with a greeting text "Hello, Guest!" and a text field below it to edit the username. Typing in the text field updates the greeting in real time.
Common Pitfalls
- Not injecting the
ObservableObjectwith.environmentObject()causes runtime crashes because the environment object is missing. - Declaring
@EnvironmentObjectin a view without the matching object in the environment leads to a crash. - Using
@ObservedObjector@StateObjectinstead of@EnvironmentObjectwhen you want shared data across many views.
swift
struct ChildView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
Text("Username: \(settings.username)")
}
}
// Wrong: Forgetting to inject environment object
// This will crash at runtime
// ChildView()
// Right: Inject environment object in parent
ChildView().environmentObject(UserSettings())Output
Crash if environment object missing; shows username text if injected properly.
Quick Reference
| Concept | Description | Usage |
|---|---|---|
| ObservableObject | Class that holds shared data and notifies views | class MyData: ObservableObject { @Published var value = 0 } |
| @EnvironmentObject | Property wrapper to access shared data in views | @EnvironmentObject var data: MyData |
| .environmentObject() | Modifier to inject shared object into view hierarchy | ContentView().environmentObject(MyData()) |
| Common Error | Missing injection causes crash | Always inject with .environmentObject() |
Key Takeaways
Use @EnvironmentObject to share observable data across many SwiftUI views without manual passing.
Inject your ObservableObject into the view hierarchy with .environmentObject() on a parent view.
Access the shared data in child views using @EnvironmentObject property wrapper.
Always ensure the environment object is injected to avoid runtime crashes.
Use @EnvironmentObject for global or widely shared data, not for local state.