如何强制NavigationLink重新创建目标视图?
问题原因
你的代码中,gameView是一个计算属性,SwiftUI会对这类视图进行缓存优化。这就导致每次通过showGameView激活导航链接时,复用的都是同一个视图实例,包括其中的MyGameModel对象,所以关闭游戏视图后再次打开,显示的还是之前的状态。
解决方案
方案1:使用NavigationStack(iOS 16+ 推荐)
iOS 16及以上版本推荐使用NavigationStack替代旧的NavigationView,通过路径管理导航栈,每次向路径中添加新元素时,会自动生成新的视图实例:
struct MenuView: View { @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { VStack { Button { // 每次点击添加新的路径元素,触发新视图创建 path.append(()) } label: { Text("Play") } } .navigationDestination(for: Void.self) { let gameModel = MyGameModel.myGameModel() ContentView() .environmentObject(gameModel) } } } }
方案2:给目标视图添加唯一ID
通过给目标视图绑定一个动态变化的id,让SwiftUI认为每次都是新视图。可以用一个计数器来实现:
struct MenuView: View { @State private var showGameView: Bool = false @State private var gameViewCounter = 0 var body: some View { NavigationView { VStack { NavigationLink( destination: gameView.id(gameViewCounter), isActive: $showGameView) { EmptyView() } Button { // 先更新计数器,再激活导航 gameViewCounter += 1 showGameView = true } label: { Text("Play") } } } .navigationViewStyle(.stack) } @MainActor @ViewBuilder private var gameView: some View { let gameModel = MyGameModel.myGameModel() ContentView() .environmentObject(gameModel) } }
方案3:将视图创建改为方法调用
把gameView从计算属性改为方法,这样每次调用方法都会创建新的视图和模型实例:
struct MenuView: View { @State private var showGameView: Bool = false var body: some View { NavigationView { VStack { NavigationLink( destination: makeGameView(), isActive: $showGameView) { EmptyView() } Button { showGameView = true } label: { Text("Play") } } } .navigationViewStyle(.stack) } @MainActor private func makeGameView() -> some View { let gameModel = MyGameModel.myGameModel() return ContentView() .environmentObject(gameModel) } }
核心原理
以上方案的本质都是让SwiftUI每次触发导航时,识别到目标视图是全新的实例,从而重新初始化视图及其关联的MyGameModel,彻底避免复用旧状态。
内容的提问来源于stack exchange,提问作者Maq
相关产品推荐
相关产品推荐

