Navigation: update multiple times per frame

After updating to NavigationStack with nested navigation links (with navigation links in a navigation destination), I see a lot of warnings in Xcode 14 beta:

Update NavigationAuthority bound path tried to update multiple times per frame.

Update NavigationAuthority possible destinations tried to update multiple times per frame.

The app often freezes when navigated with a NavigationLink. Do others see these problems?

I ran into the same problem and was able to resolve it by replacing the "NavigationLink(value:" with a button instead:

// Used for programmatic navigation
@EnvironmentObject var router: Router


Button {
    router.path.append(SettingsView())
} label: {
    Label("Settings", systemImage: "gearshape")
} 


class Router: ObservableObject {
     @Published var path = [Destination]()

     func goBack() {
         // Navigate back to the previous view
         path.removeLast()
     }
   
     func goToRoot() {
         // Navigate back all the way to the root view
         path = []
     }
}


I am also seeing the same message. In a mirror situation (almost identical code in a Row/Detail situation where rows navigate to editor details), everything works fine. But in the second situation, I get the message "Update NavigationRequestObserver tried to update multiple times per frame" and 100% CPU hang. I've ripped out everything, so there's barely anything going on, and the problem persists. The differentiator between hangs/doesn't hang seems to be whether a closure in the editor (and one that has not even been invoked) captures a state variable in that editor (View). This makes no sense to me. There must be some strange stuff going on behind the scenes.

I have tried Button vs Navigationlink, to no avail. For now, I also have to conclude this is a swift or swiftUI bug.

FWIW, I am using a NavigationStack with a NavigationPath to control it. I'm always using .navigationDestination to set up the hierarchy. Xcode Version 14.2 (14C18)

I was able to remove the runtime warning using a button instead of a navigation link, similar to RandoCorleones' suggestion. I toggled an isPresented State variable within the button that triggered a navigationDestination.

.navigationDestination(isPresented: $isPresented, destination: {
                TriggeredView()
            })

Maybe this helps anyone:

I was running into this issue and at least found one thing in my code causing this.

I had ViewModels that were handed over to the detail view called by NavigationLink(value:) In the Detail View those ViewModel were

@ObservedObject var someViewModel : SomeViewModel

thus making SwiftUI rerender and recreate that ViewModel in an infinite loop

changing that to a StateObject:

@StateObject var someViewModel : SomeViewModel

helped (in that special case)

I encountered this problem with my NavigationStack when using both NavigationLink with values and without. The navigationStack had to be all NavigationLinks with values or without, I could not mix the two.

NavigationLink(destination: ItemDetail(item: equipItem)) {
                       Text("\(equipItem.name)")
                    }

NavigationLink with no value

NavigationLink(equipItem.name, value: equipItem)
                        .navigationTitle(categoryName)

//
code ....
//

.navigationDestination(for: equipment.self, destination: { equipItem in
                    ItemDetail(item: equipItem)

NavigationLink with a value

According to Google Bard 🤖 this can happen if you are using an ObservableObject @Published property as the path: Binding on a NavigationStack and you are changing the value of the property in the same frame.

⚠️ Something like this triggered the runtime warning for me, despite everything still working properly:

// ViewModel
class MyModelObject: ObservableObject {
    @Published var path: [MyObject] = []
    ...
}


// View
@StateObject var model = MyModelObject()

var body: some View {
    NavigationView(path: $model.path) {
    ...

✅ In the end, the following fixed the runtime warning, I had to make path: read from a @State property Binding and still communicate to the view model using the onChange function.

// ViewModel
class MyModelObject: ObservableObject {
    @Published var path: [MyObject] = []

    ...

    // Useful for manipulating a property observed by other components.
    func update(_ path: [MyObject]) {
        self.path = path
    }
}

// View
@State var presentedPath: [MyObject] = []
@StateObject var model = MyModelObject()

var body: some View {
    NavigationView(path: $presentedPath) {
        ...
    }.onChange(of: presentedPath) { newPath in
        model.update(path: newPath)
    }
}

Hi all. There no solution yet?

@2Jumper3 I was experiencing this issue before even adding any destinations to my NavigationPath.

Switching from NavigationPath to add my routes to an array of Routes resolved my issue. Hope this helps.

From:

var path = NavigationPath()

To:

var path: [Route] = [Route]()
Navigation: update multiple times per frame
 
 
Q