Sharing State Across Views With Environment Objects
Written by Team Kodeco
While ObservableObject
and ObservedObject
are great for sharing state between views, they require you to pass the state manually from parent to child. But what if you want to share data across multiple views in your app without explicitly passing it around? That’s where environment objects come in.
SwiftUI’s EnvironmentObject
property wrapper provide a way to share data across your entire app. You can think of them as a global store for your data that any view can access. This is particularly useful when you have deeply nested views and don’t want to pass data through multiple layers.
To use an environment object, you first need to define your data model as an ObservableObject
. For example, let’s create a GameSettings
object that holds the score of a game.
class GameSettings: ObservableObject {
@Published var score = 0
}
Then, in the root of your app, you provide this object to your view hierarchy using the environmentObject
modifier.
struct ContentView: View {
var body: some View {
GameView()
.environmentObject(GameSettings())
}
}
Now, any view in the hierarchy can access GameSettings
using the EnvironmentObject
property wrapper.
struct GameView: View {
@EnvironmentObject var settings: GameSettings
var body: some View {
VStack {
Text("Score: \(settings.score)")
Button("Increment Score") {
settings.score += 1
}
}
}
}
Here’s what the preview looks like:
In this example, GameView
has access to the GameSettings
object and can update the score. When the button is pressed, the score is incremented, and the Text
view is automatically updated because it observes the GameSettings
object.
Note: The
EnvironmentObject
property wrapper doesn’t provide a default value. The object must be provided somewhere in the ancestor views using.environmentObject(_:)
or your app will crash.