I am building a navigation system based on NavigationStack
and modifiers .navigationDestination()
.
What I am trying to achieve: I need to build a View
hierarchy with navigation:
- ContentView
- ViewA.navigationDestination()
- ViewB.navigationDestination()
- ...
Each level of view hierarchy can contains it's own .navigationDestination()
to handle navigation events. Navigation event is triggered by appending NavigationPath of top level NavigationStack.
In WWDC 2022 video about navigation it is confirmed that we can use nested navigationDestination modifiers.
The problem: when button "Down to B"
pressed, I can see ViewB()
is pushed. But also I see @StateObject
StoreB()
is initialized, then deinitialized, and then initialized again.
Question: Why this code triggering multiple initialization of StateObject StoreB? Is it normal behaviour or it's a SwiftUI bug?
I tried to place navigationDestination
//B
right after //A
, and there is no repeated init. I can go this way, but I like the idea of describing navigation in place where it's belong.
Can you suggest some way to work around this multiple init?
struct ContentView: View {
@State var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
ViewA(path: $path)
}
}
}
// MARK: - View A
struct ViewA: View {
@Binding var path: NavigationPath
var body: some View {
Button("Down to B") {
path.append(RouteToB())
}
.navigationDestination(for: RouteToB.self) { route in //A
ViewB(path: $path)
}
}
struct RouteToB: Hashable { }
}
// MARK: - View B
struct ViewB: View {
@Binding var path: NavigationPath
@StateObject var storeB = StoreB()
var body: some View {
Button("Down to C") {
path.append(RouteToC())
}
.navigationDestination(for: RouteToC.self) { route in //B
Color.green
}
}
struct RouteToC: Hashable { }
class StoreB: ObservableObject {
private let value = 8
init() {
print("+++ Store B inited")
}
deinit {
print("--- Store B deinited")
}
}
}