SwiftUI崩溃:尝试返回至不存在的目标页面
这个错误的核心原因是:点击完成按钮时,OnboardingView的NavigationView仍在处理导航栈状态,此时直接切换到TabView会导致系统试图pop一个已被销毁的导航目标,触发崩溃。以下是几种可行的解决方案:
方案一:延迟切换视图,给导航栈留足清理时间
在完成引导后,不要立即切换视图,而是延迟几十毫秒,确保NavigationView的导航栈状态处理完毕:
// OnboardingView中的完成按钮逻辑 Button("完成") { // 先完成当前导航的dismiss操作(如果存在多级页面) dismiss() // 延迟更新状态,避免视图突然销毁导致的导航冲突 DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { onboardingCompleted = true } }
方案二:使用NavigationStack替代NavigationView(iOS 16+)
iOS 16推出的NavigationStack采用更可靠的状态管理机制,能避免旧版NavigationView的栈冲突问题:
// 重构OnboardingView使用NavigationStack struct OnboardingView: View { @Binding var onboardingCompleted: Bool var body: some View { NavigationStack { // 引导流程页面内容... Button("完成") { onboardingCompleted = true } } } }
方案三:用平滑过渡替代直接条件切换
避免直接通过if/else销毁和重建视图,改用ZStack配合透明度和层级控制实现平滑切换,减少状态突变:
struct ContentView: View { @State private var isSignedIn = false @AppStorage("onboardingCompleted") var onboardingCompleted: Bool = false var body: some View { ZStack { OnboardingView(onboardingCompleted: $onboardingCompleted) .opacity(shouldShowMain ? 0 : 1) .zIndex(shouldShowMain ? 0 : 1) MainView() .opacity(shouldShowMain ? 1 : 0) .zIndex(shouldShowMain ? 1 : 0) } .onAppear() { signIn() } } private var shouldShowMain: Bool { onboardingCompleted && isSignedIn } }
方案四:手动清理NavigationView的导航栈
如果仍需使用NavigationView,可以在切换前手动将导航栈pop到根视图:
Button("完成") { // 获取当前导航控制器并pop到根 if let navController = UIApplication.shared.connectedScenes .compactMap({ $0 as? UIWindowScene }) .first?.windows .first?.rootViewController as? UINavigationController { navController.popToRootViewController(animated: true) } DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { onboardingCompleted = true } }
内容的提问来源于stack exchange,提问作者Vojta Böhm
相关产品推荐
相关产品推荐

