Skip to content

SwiftUI Navigation Destination

There are multiple ways to navigate from one view to another in SwiftUI. Here we look at the differences in subview lifecycle behavior between

  1. using a boolean isPresented binding;
  2. using a NavigationPath.

The navigation is performed when a binding to a boolean state variable becomes true.

struct MainView: View {
@State private var isSubviewVisible = false
var body: some View {
NavigationStack {
VStack {
Text("Main View")
Button {
print("Button tapped")
isSubviewVisible.toggle()
} label: {
Text("To subview")
}
}
.navigationDestination(isPresented: $isSubviewVisible) {
SubView()
}
}
}
}
struct SubView: View {
var body: some View {
VStack {
Text("Subview")
}
}
}
  • The subview is instantiated when the parent view’s body is evaluated (assuming no conditional branching).
  • Visibility is controlled by a boolean binding, but instantiation is not.
  • The subview may be created long before navigation actually occurs.
  • The same subview instance is reused across repeated navigations.

The navigation destination is evaluated at the moment the value of the navigation path changes.

struct MainView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
VStack {
Text("Main View")
Button {
print("Button tapped")
path.append("subview")
} label: {
Text("To subview")
}
}
.navigationDestination(for: String.self) { name in
if name == "subview" {
SubView()
}
}
}
}
}
struct SubView: View {
var body: some View {
VStack {
Text("Subview")
}
}
}
  • The subview is instantiated only when the navigation path changes.
  • Instantiation happens at the moment of navigation.
  • When navigating back, the subview is deinitialized and not reused across navigations.
Environment:
Xcode 16.0
Swift 5.10
iOS 18.0