SwiftUI中NavigationPath无法追加ViewModel致导航中断求助
导航栈追加ViewModel时应用崩溃问题排查
问题描述
我通过NavigationPath追加ViewModel实现页面导航,相关逻辑和.navigationDestination配置如下。当在ContentView(导航路径的第二个视图,BumperScreen的子视图)中点击“继续”按钮,尝试将WelcomeScreenViewViewModel添加到path时,应用直接停止运行。我用相同导航方法创建了测试项目,可正常进行多次甚至近乎无限导航,无法复现当前项目的问题,不清楚两个项目表现差异的原因。
相关代码
BumperScreen视图
struct BumperScreen: View { @State private var path = NavigationPath() @StateObject var viewModel: BumperScreenViewModel @StateObject var sheetManager = SheetManager() init(viewModel: @autoclosure @escaping () -> BumperScreenViewModel) { self._viewModel = .init(wrappedValue: viewModel()) } var body: some View { if isDoneOnboarding { HomeView() .environmentObject(sheetManager) } else { NavigationStack(path: $path) { ZStack { Color(.Gold) .ignoresSafeArea() VStack { if show { Spacer() loadAnimation .frame(width: 150, height: 150) .task { try? await viewModel.getDataFromAPI() try? await Task.sleep(for: Duration.seconds(1)) path.append(ContentViewViewModel()) doneLoading.toggle() show.toggle() } Spacer() } else if doneLoading { EmptyView() } else { launchAnimation } } .navigationDestination(for: ContentViewViewModel.self) { model in ContentView(viewModel: model, path: $path) .environmentObject(sheetManager) } } } } } }
ContentView视图
struct ContentView: View { @EnvironmentObject var sheetManager: SheetManager @StateObject var viewModel: ContentViewViewModel @Binding var path: NavigationPath var body: some View { ZStack { Color(.trulliGold) .ignoresSafeArea() VStack { Spacer() headerStatement Spacer() VStack { privacyPolicy bluetoothPolicy locationsPolicy notificationsPolicy apprunningPolicy } Spacer() Spacer() continueButton } } .popup(with: sheetManager) .navigationBarBackButtonHidden() } var continueButton: some View { Button(action: { print("pressed") path.append(WelcomeScreenViewViewModel()) }) { Text("CONTINUE") } .navigationDestination(for: WelcomeScreenViewViewModel.self) { model in WelcomeScreenView(viewModel: model, path: $path) } } }
WelcomeScreenView视图
struct WelcomeScreenView: View { @StateObject var viewModel: WelcomeScreenViewViewModel @Binding var path: NavigationPath var body: some View { ZStack { Color(.trulliGold) .ignoresSafeArea() VStack(alignment: .center, spacing: 8) { header Spacer() tabView Spacer() Spacer() nextButton closeButton } } .navigationDestination(for: SetupGuideSpeakerSearchViewViewModel.self) { model in SetupGuideSpeakerSearchView(viewModel: model, path: $path ) } .navigationBarBackButtonHidden() } }
排查方向
- 确保ViewModel遵循Hashable协议:
NavigationPath要求所有追加的元素必须遵循Hashable,检查WelcomeScreenViewViewModel是否正确实现该协议(包括所有存储属性的哈希逻辑),测试项目中的ViewModel可能默认满足该条件,但当前项目可能遗漏。 - 调整navigationDestination的位置:不要将
.navigationDestination附加在按钮上,应将其移到ContentView的根视图层级(比如ZStack之后),或者统一放在BumperScreen的NavigationStack内部。SwiftUI需要在导航栈的上下文范围内识别目的地映射,嵌套在按钮中可能导致解析失败引发崩溃。 - 排查环境对象或弹窗冲突:暂时移除
.popup(with: sheetManager)代码,测试点击“继续”按钮是否仍崩溃,排除SheetManager状态异常导致的问题。 - 检查ViewModel初始化逻辑:查看
WelcomeScreenViewViewModel的初始化方法是否存在未处理的可选值、资源加载错误等问题,这些异常可能在追加到path时触发崩溃。 - 打印NavigationPath状态:在点击按钮时输出
print(path),查看path是否包含无效或重复元素,确认导航栈状态是否正常。 - 核对SwiftUI版本:确认当前项目和测试项目使用的Xcode/SwiftUI版本一致,某些旧版本的NavigationStack存在已知bug,升级到最新稳定版可能解决问题。
内容的提问来源于stack exchange,提问作者kenada97
相关产品推荐
相关产品推荐

