Problem with DestinationBuilderView. Twice init view
Hello, I'm encountering an issue using NBNavigationStack with an enum state. For example, I have two flows: main and authorization. In the body of my ContentView, there is a state with two cases, main and auth, controlled by a singleton session. Both cases are wrapped in NBNavigationStack.
In my Auth flow, there is a root view where I can push the Login View with a TextField and a ViewModel stored as a StateObject. When I enter credentials and press the button, my TextField is still the first responder. If the credentials are okay, I change the state of my ContentView using the singleton.
However, here is the problem. While the state is changing on the main flow, my Login View is initializing again (it should not), but it won't show on the screen. Right after changing the screen, it could crash with this error (only if the view is complex and only on iOS 15): Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1b8d1abd0).
The issue is not just with TextField; it could be anything on the UI, even the .sheet modifier.
I tried to dig into the library and found out that the problem is in DestinationBuilderView's body. Maybe it's possible to move destinationBuilder.build(data) outside of this view, resolve it on push, and inject it into DestinationBuilderView.
And one more thing. If I use internalTypedPath, I will receive crash on changing state. Because on second init there is nothing in DestinationBuilderHolder.builders dictionary.
Sample project with bug: NavigationBug.zip
Hi @demonukg - thanks for raising this, and the sample project! I wasn't able to reproduce the crash in the sample project on iOS 15.5 sim, but I could see the re-initialisation of the view model. From what I see, in your navigation destination builder:
.nbNavigationDestination(for: AuthScreens.self) { screen in
switch screen {
case .login:
Login().view
case .enterEmail:
Email().view
}
}
A new view model will be created each time Login().view is called in the destination builder closure. This closure is called regularly - each time a new item is added to the stack, the closure will be called for each screen on the stack. So to avoid creating new view models each time, you would need to store the view model in the stack - e.g.:
enum AuthScreens: NBScreen {
case enterEmail(EmailModel)
case login(LoginModel)
}
I made a change so that the closure is only invoked once for the same data at the same index, shipped in v0.9.4. Thanks for your patience!