I am running into an example where if you have a View that has a NavigationStack in it, and it appears and disappears based on a conditional, it doesn't seem to get fully torn down?
This appears to matter most when it is also initializing a ViewModel, because it will reinit without deiniting.
So for example
struct ContentView: View {
@State var showNavStack:Bool = false
var body: some View {
Button("ShowHide") {
showNavStack.toggle()
}.padding(20)
if showNavStack {
SimpleRootView()
}
}
}
With the NavigationStack view
import SwiftUI
class DoNothingVM:ObservableObject {
deinit {
print("ViewModel DEINIT")
}
init() {
print("ViewModel INIT")
}
}
struct SimpleRootView: View {
@StateObject var viewModel = DoNothingVM()
@State var path = NavigationPath()
let int = Int.random(in: 0...100)
var body: some View {
NavigationStack(path: $path) {
VStack {
Text("Hello \(int)")
Button("Go Forward") {
path.append(Int.random(in: 0...100))
}
}.navigationDestination(for: Int.self) { int in
DetailIntView(int: int, path: $path)
}.navigationTitle("\(int)")
}
}
}
struct DetailIntView:View {
let int:Int
@Binding var path:NavigationPath
var body: some View {
VStack {
Text("Hello \(int)")
Button("Go Forward") {
path.append(Int.random(in: 0...100))
}
}.navigationTitle("\(int)")
}
}
Will lead to multiple calls to a DoNothing
init every time the showNavStack
is toggled to true
, but no deinit
when toggled to false
. Multiples remain in memory.
"So don't do that" is fine for me in my case, but I'm wondering if this is expected behavior? Is it simply that SwiftUI
only expects One and Only One NavigationStack
per app and that it will be the only thing in charge? I haven't tested it, but what does that mean for coming back out of the background? This seems like a bug, but it might also be my misunderstanding.
Project where I'm messing around with this here: https://github.com/carlynorama/NavigationExplorer