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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:59:52