SwiftUI弹窗关闭后如何立即刷新Core Data列表?
Core Data 添加数据后列表不实时更新的解决方案
问题描述
我用Core Data实现水果的永久存储和列表展示,包含ContentView主界面和作为弹窗的SecondScreen。在SecondScreen输入水果点击保存后,希望ContentView的列表能立刻显示新添加的水果,但现在点击保存后新水果不会马上出现,必须重启应用才能看到。我尝试在ContentView里加了@State变量refresh并和SecondScreen绑定,点击保存时切换这个变量触发刷新,但没效果。
问题分析
- 核心问题是ContentView和SecondScreen各自创建了独立的
CoreDataViewModel实例:SecondScreen里添加数据的操作是在自己的vm实例上执行的,ContentView的vm完全感知不到数据变化。 - 你尝试的
refresh变量无效,因为ContentView的列表是基于vm.savedEntities渲染的,refresh变量没有关联到重新获取数据的逻辑,而且就算关联了,两个vm实例的数据本来就是分开的,刷新也拿不到新数据。
解决方案
- 让SecondScreen复用ContentView的
CoreDataViewModel实例,不要自己新建。 - 移除多余的
refresh变量,利用@Published属性的自动刷新机制,当savedEntities更新时SwiftUI会自动更新列表。
修改后的代码
ContentView 结构体
struct ContentView: View { // sheet控制变量 @State var showSheet: Bool = false @StateObject var vm = CoreDataViewModel() var body: some View { NavigationView { VStack(spacing: 20) { Button(action: { showSheet.toggle() }, label: { Text("Add Fruit") }) List { ForEach(vm.savedEntities) { entity in Text(entity.name ?? "NO NAME") } } } .navigationTitle("Fruits") .sheet(isPresented: $showSheet, content: { // 将ContentView的vm传递给SecondScreen SecondScreen(vm: vm) }) } } }
SecondScreen 结构体
struct SecondScreen: View { // 接收ContentView传递过来的ViewModel实例 @ObservedObject var vm: CoreDataViewModel @Environment(\.dismiss) var dismiss // iOS15+ 推荐使用该API关闭弹窗 @State var textFieldText: String = "" var body: some View { TextField("Add fruit here...", text: $textFieldText) .font(.headline) .padding(.horizontal) Button(action: { guard !textFieldText.isEmpty else { return } vm.addFruit(text: textFieldText) // 使用共享的vm添加数据 textFieldText = "" dismiss() // 关闭弹窗 }, label: { Text("Save") }) } }
效果说明
修改后,SecondScreen使用的是和ContentView同一个CoreDataViewModel实例,添加数据后调用的saveData方法会重新获取数据并更新@Published修饰的savedEntities,SwiftUI会自动检测到这个变化并刷新ContentView的列表,实现添加数据后的实时更新。
内容的提问来源于stack exchange,提问作者Sutton
相关产品推荐
相关产品推荐

