SwiftUI中List视图的Core Data条目无法正常删除问题
SwiftUI Core Data列表删除异常修复
问题现象
SwiftUI应用的LiftEventsView列表展示Core Data存储的LiftEvent条目,执行滑动删除操作时:
- 第一次滑动后,目标行并未立即消失,仅
eventReps、eventWeight和formattedOneRepMax的内容清空 - 必须执行第二次滑动操作,才能彻底删除该行
核心原因
- 数据获取忽略未提交变更:
DataController的liftEventsForSelectedFilter()方法中,给fetchRequest设置了includesPendingChanges = false,导致删除操作后立即查询时,无法获取到上下文的未提交删除变更,列表仍会展示已删除的条目(此时条目已变成fault状态,所以内容为空)。 - 视图无法监听数据变化:当前通过每次调用方法获取列表数据,而非使用
@Published属性存储,SwiftUI无法自动感知Core Data数据的变更,无法触发视图刷新。
修复步骤
1. 修改DataController,添加可监听的列表数据属性
在DataController中添加@Published属性存储过滤后的事件数组,替代每次调用方法查询:
class DataController: ObservableObject { let container: NSPersistentContainer @Published var selectedLiftEvent: LiftEvent? // 添加可监听的列表属性 @Published var filteredLiftEvents: [LiftEvent] = [] // ... 其他原有代码 // 加载过滤后的事件列表 func loadFilteredLiftEvents() { let request = LiftEvent.fetchRequest() // 移除includesPendingChanges = false,确保能获取未提交变更 filteredLiftEvents = (try? container.viewContext.fetch(request)) ?? [] } func delete(_ object: NSManagedObject) { container.viewContext.delete(object) save() // 删除后刷新列表数据,触发视图更新 loadFilteredLiftEvents() Logger.coreData.debug("Deleted lift event \(object)") } func liftEventsForSelectedFilter() -> [LiftEvent] { loadFilteredLiftEvents() return filteredLiftEvents } init(inMemory: Bool = false) { // ... 原有初始化代码 // 初始化时加载数据 loadFilteredLiftEvents() } }
2. 更新LiftEventsView,使用@Published属性渲染列表
修改LiftEventsView中的ForEach,直接使用dataController.filteredLiftEvents:
struct LiftEventsView: View { @EnvironmentObject var dataController: DataController let viewModel = LiftEventRowViewModel(calculator: Calculator()) var body: some View { List { // 改为使用可监听的filteredLiftEvents数组 ForEach(dataController.filteredLiftEvents) { liftEvent in LiftEventRow(liftEvent: liftEvent, viewModel: viewModel) } .onDelete(perform: delete) } .navigationTitle("Lift Log") // 视图出现时刷新数据 .onAppear { dataController.loadFilteredLiftEvents() } } func delete(_ offsets: IndexSet) { for offset in offsets { let item = dataController.filteredLiftEvents[offset] dataController.delete(item) } } }
3. 移除所有fetchRequest的includesPendingChanges设置
确保所有查询Core Data的请求都不要设置includesPendingChanges = false,保证能实时获取上下文的变更,包括未提交的删除操作。
验证效果
修复后执行滑动删除操作:
- 第一次滑动后,Core Data上下文删除条目并保存,同时
filteredLiftEvents更新,视图立即刷新,目标行直接消失 - 日志中删除后查询的事件数量会立即变为正确值,无需第二次操作
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

