You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 13:28:17