使用Point-Free的swiftui-navigation时深层路由初始化异常问题
问题现象
使用Point-Free的swiftui-navigation库时:
- 初始化到第一屏(
ContentView(viewModel: .init(route: nil)))或第二屏(ContentView(viewModel: .init(route: .second(route: nil))))时,导航功能正常。 - 初始化到第三屏(
ContentView(viewModel: .init(route: .second(route: .third))))时,应用先显示第三屏,随后自动退回第二屏。
问题原因
问题出在NavigationLink的onNavigate回调实现上。当初始化深层路由时,SwiftUI在同步导航状态的过程中会触发onNavigate,而当前代码中直接将第二屏的子路由重置为nil:
// ContentView中错误的onNavigate实现 onNavigate: { isActive in viewModel.route = isActive ? .second(route: nil) : nil }
这会覆盖掉初始化时传入的.third子路由,导致第三屏被自动弹出。
同理,SecondView中的onNavigate也存在类似逻辑,不过主要触发点在ContentView的回调。
解决方案
修改onNavigate的逻辑,仅在用户主动关闭导航(比如点击返回按钮)时更新路由,初始化时保留原有的深层路由结构。
修改后的完整代码
import SwiftUINavigation import SwiftUI class ContentViewModel: ObservableObject { @Published var route: Route? = nil init(route: Route? = nil) { self.route = route } enum Route: Equatable { case second(route: SecondViewModel.Route?) } } struct ContentView: View { @StateObject var viewModel: ContentViewModel var body: some View { NavigationView { NavigationLink( unwrapping: $viewModel.route, case: /ContentViewModel.Route.second, onNavigate: { isActive in // 仅在关闭导航时清空路由,打开时保留原有子路由 if !isActive { viewModel.route = nil } } ) { $route in // 绑定子路由,让SecondViewModel能同步更新 SecondView(viewModel: .init(route: route)) } label: { Text("One") } } } } class SecondViewModel: ObservableObject { @Published var route: Route? = nil init(route: Route? = nil) { self.route = route } enum Route: Equatable { case third } } struct SecondView: View { @StateObject var viewModel: SecondViewModel var body: some View { NavigationLink( unwrapping: $viewModel.route, case: /SecondViewModel.Route.third, onNavigate: { isActive in // 同样仅在关闭时清空路由 if !isActive { viewModel.route = nil } } ) { $route in Text("Three") } label: { Text("Two") } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView(viewModel: .init(route: .second(route: .third))) } }
关键修改点
- ContentView的onNavigate:移除了打开导航时重置子路由的逻辑,仅在
isActive为false(用户关闭导航)时清空viewModel.route。这样初始化时传入的.second(route: .third)会被完整保留,不会被覆盖。 - SecondView的onNavigate:同理,仅在关闭第三屏时清空子路由,避免初始化时的误触发。
- 子路由绑定:通过
$route将ContentView的子路由绑定到SecondViewModel,保证深层路由的状态能正确同步。
这样修改后,初始化到第三屏时,路由结构会被完整保留,不会出现自动回退的问题。
内容的提问来源于stack exchange,提问作者Sergio
相关产品推荐
相关产品推荐

