SwiftUI中fullScreenCover重复调用致视图状态丢失的解决方法咨询
SwiftUI 解决弹窗视图ViewModel状态丢失问题
现有实现的问题
你的代码里,fullScreenCover的内容闭包会在MainView的body每次刷新时重新执行(比如mainViewModel.text变化触发更新),而ViewsFactory.someView()每次调用都会创建全新的SomeViewModel实例,导致之前的状态完全丢失。这就是核心问题所在。
正确处理方式
下面提供几种可靠的解决方案,根据你的业务场景选择:
1. 用@StateObject持有ViewModel(推荐,iOS14+)
@StateObject会确保ViewModel实例的生命周期与当前View绑定,无论body刷新多少次,实例都不会重建。
修改后的MainView代码:
struct MainView: View { @ObservedObject var mainViewModel: MainViewModel @State var isPresent: Bool = false // 用@StateObject持有ViewModel,保证实例唯一 @StateObject private var someViewModel = SomeViewModel(DI1, DI2, DI3, DI4) var body: some View { VStack { Text(mainViewModel.text) Button("press me", action: { isPresent = true }) } .fullScreenCover(isPresented: $isPresent) { SomeView(viewModel: someViewModel) } } }
2. 使用fullScreenCover的item绑定版本
通过绑定一个可选类型的ViewModel实例,只在第一次需要展示时初始化,后续不会重建。需要让SomeViewModel遵循Identifiable协议:
struct MainView: View { @ObservedObject var mainViewModel: MainViewModel @State private var someViewModel: SomeViewModel? var body: some View { VStack { Text(mainViewModel.text) Button("press me", action: { // 仅当ViewModel未初始化时创建实例 if someViewModel == nil { someViewModel = SomeViewModel(DI1, DI2, DI3, DI4) } }) } // 通过item绑定控制弹窗展示,ViewModel实例由父级管理 .fullScreenCover(item: $someViewModel) { viewModel in SomeView(viewModel: viewModel) } } } // 让SomeViewModel遵循Identifiable协议 extension SomeViewModel: Identifiable { // 可以用UUID作为唯一标识,或者用业务相关的唯一属性 var id: UUID { UUID() } }
3. 将ViewModel提升到父层级管理
如果SomeViewModel的状态需要和MainViewModel共享,或者需要更长的生命周期,可以让MainViewModel持有它:
class MainViewModel: ObservableObject { @Published var text: String = "" // 由MainViewModel管理SomeViewModel的生命周期 var someViewModel: SomeViewModel? } struct MainView: View { @ObservedObject var mainViewModel: MainViewModel @State var isPresent: Bool = false var body: some View { VStack { Text(mainViewModel.text) Button("press me", action: { if mainViewModel.someViewModel == nil { mainViewModel.someViewModel = SomeViewModel(DI1, DI2, DI3, DI4) } isPresent = true }) } .fullScreenCover(isPresented: $isPresent) { if let viewModel = mainViewModel.someViewModel { SomeView(viewModel: viewModel) } } } }
总结
核心思路就是让ViewModel的生命周期脱离body的刷新循环,通过@StateObject、父级持有或item绑定的方式,确保实例不会被重复创建,从而保留状态。
内容的提问来源于stack exchange,提问作者thedp
相关产品推荐
相关产品推荐

