Suppose I have a simple @Observable like
@Observable class Navigation {
var path = NavigationPath()
}
And make an environment in my app structure like the migrating to observable docs recommend
@main
struct ObservableTestApp: App {
@State private var navigation = Navigation()
var body: some Scene {
WindowGroup {
ContentView()
.environment(navigation)
}
}
}
I find that trying to use the @Environment from my view with NavigationStack like
struct ContentView: View {
@Environment(Navigation.self) private var navigation
var body: some View {
NavigationStack(path: $navigation.path) {
...
}
}
}
Raises this compiler error
Cannot find ‘$navigation’ in scope
If we defined the @State on the ContentView instead, there is no compiler error.
Additionally, if I revert this to pre iOS 17 @ObservableObject using @StateObject and @EnvironmentObject (etc) then the compiler is fine with it. So it seems to be an issue with the new @Observable. Or perhaps my usage of it.
I understand there is an easy workaround but @ObservableObject behaving differently to @Observable is worth questioning.
>Solution :
You need to use Bindable to get a bindable version of navigation.
struct ContentView: View {
@Environment(Navigation.self) private var navigation
var body: some View {
@Bindable var navigation = navigation
NavigationStack(path: $navigation.path) {
// ...
}
}
}
See the documentation, including this example:
struct TitleEditView: View {
@Environment(Book.self) private var book
var body: some View {
@Bindable var book = book
TextField("Title", text: $book.title)
}
}