SwiftUI嵌套Navigation导航跳转后页面快速自动返回问题排查
问题原因
跳转后目标页自动关闭返回的核心逻辑:
- 所有导航层级的AView共用同一个
SafeFileViewModel实例的arrayOfFiles作为List数据源。 - 每个AView在
onAppear生命周期中都会修改ViewModel的additionPath属性,并调用takeArrayOfItems()更新全局共享的arrayOfFiles。 - 点击NavigationLink跳转到下一级AView时,新页面的onAppear触发全局数组更新,导致上一级页面的List重新加载,所有列表行(包含触发跳转的NavigationLink所在行)被重新初始化,SwiftUI判定原导航触发源失效,自动弹出导航栈返回上一级,最终表现为页面刚打开就自动关闭。
空白测试项目未复现问题的原因:测试项目的List使用静态固定范围0..<5作为数据源,子页面加载时不会修改上层页面依赖的数据源,不会触发上层List意外刷新,因此不会出现导航自动回退。
代码中额外存在一处会引发状态不一致的问题:BView中将外部传入的currentFile、currentLocation参数用@State修饰。@State设计为View的私有状态,外部传参变化时不会自动同步,会导致View身份识别异常。
修复方案
- 为每一层导航的AView维护独立的本地文件列表状态,禁止所有层级共用ViewModel中的全局
arrayOfFiles,避免子页面加载时触发上层List刷新。
修正后的AView代码参考:struct AView: View { @ObservedObject var safeFileVM: SafeFileViewModel // 当前层级专属文件列表,独立存储不跨层级共享 @State private var currentLevelFiles: [MyFile] = [] @State var currentLocation = "" @State var currentFolder: String = "Safe File" var body: some View { List(currentLevelFiles, id: \.id) { folderItem in BView(safeFileVM: safeFileVM, currentFile: folderItem, currentLocation: currentLocation) } .navigationTitle(currentFolder) .onAppear { safeFileVM.additionPath = currentLocation // 拉取当前路径文件后存入本地状态,不修改全局共享数组 currentLevelFiles = safeFileVM.takeArrayOfItems() } } } - 移除BView中参数前错误的
@State修饰,外部传入的只读参数直接用let声明,避免状态不同步导致的View身份识别错误。
修正后的BView代码参考:struct BView: View { @ObservedObject var safeFileVM: SafeFileViewModel let currentFile: MyFile let currentLocation: String var body: some View { VStack { if currentFile.typeOfFile == "folder" { NavigationLink(currentFile.fileName) { AView(safeFileVM: safeFileVM, currentLocation: currentLocation + "/" + currentFile.fileName, currentFolder: currentFile.fileName) } .isDetailLink(false) } else { Text(currentFile.fileName) } } } } - iOS 16及以上系统推荐方案:替换老旧的
NavigationView为NavigationStack,通过navigationDestination统一管理路由跳转,从框架层面避免List刷新导致的导航栈异常。
内容的提问来源于stack exchange,提问作者Ufuk Köşker
相关产品推荐
相关产品推荐

