Sharing @Observables through the environment

By Brendan

First, you want an Observable class.

@Observable
class Player {
    var name = "Anonymous"
    var highScore = 0
}

In your top-level View, you want a @State var and you want to stick it in the subviews via enviornment(), thus:

struct ContentView: View {
    @State private var player = Player()

    var body: some View {
        VStack {
            Text("Welcome!")
            HighScoreView()
        }
        .environment(player)
    }
}

Any sub-view (or sub-sub-view or sub-sub-sub-sub-view etc) can then read that var from the Enviroment, thus:

struct HighScoreView: View {
    @Environment(Player.self) var player

    var body: some View {
        @Bindable var player = player
        Stepper("High score: \(player.highScore)", value: $player.highScore)
    }
}

Note the additional @Bindable inside the view body. That arguably shouldn’t be necessary, but for iOS 17 at least, it is required if you want to read AND WRITE to the var, like our Stepper does.

The extra @Bindable var player = player is NOT needed if you’re just reading from the var.

See Paul 5/12 for more.