NavigationPath doesn't work with the @Observable macro iOS 17

Hello! I'm not able to push a view into a stack using new @Observable macro.

import SwiftUI
import Observation

@Observable class NavigationModel {
    var path = NavigationPath()
}

struct ContentView: View {
    @State var navigationModel: NavigationModel = NavigationModel()

    var body: some View {
        NavigationStack(path: $navigationModel.path) {
            VStack {
                Button {
                    navigationModel.path.append("Text")
                } label: {
                    Text("Go to the next screen")
                }
            }
            .navigationDestination(for: String.self) { item in
                Text("Pushed view")
            }
        }
    }
}

Everything works fine when I use ObservableObject with @Published properties:

class NavigationModel: ObservableObject {
    @Published var path = NavigationPath()
}

struct ContentView: View {
    @StateObject var navigationModel: NavigationModel = NavigationModel()

    var body: some View {
        NavigationStack(path: $navigationModel.path) {
            Button {
                navigationModel.path.append("Text")
            } label: {
                Text("Go to the next screen")
            }
            .navigationDestination(for: String.self) { item in
                Text("Pushed view")
            }
        }
    }
}

Accepted Reply

With the new Observation APIs in SwiftUI, you no longer need to use @StateObject to initialise the observable objects. You also don't need to use @State like you are doing. You can simply do this:

let navigationModel = NavigationModel()

The Observable macro does the rest.


However, the NavigationStack requires a binding to a path and your navigationModel object cannot provide one. There is a solution and that is through the @Bindable property wrapper, used like this:

@Bindable var navigationModel = NavigationModel()

Now you can get bindings from properties within that object.

Replies

With the new Observation APIs in SwiftUI, you no longer need to use @StateObject to initialise the observable objects. You also don't need to use @State like you are doing. You can simply do this:

let navigationModel = NavigationModel()

The Observable macro does the rest.


However, the NavigationStack requires a binding to a path and your navigationModel object cannot provide one. There is a solution and that is through the @Bindable property wrapper, used like this:

@Bindable var navigationModel = NavigationModel()

Now you can get bindings from properties within that object.