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

SwiftUI中List视图的Core Data条目无法正常删除问题

SwiftUI Core Data列表删除异常修复

问题现象

SwiftUI应用的LiftEventsView列表展示Core Data存储的LiftEvent条目,执行滑动删除操作时:

  • 第一次滑动后,目标行并未立即消失,仅eventReps、eventWeight和formattedOneRepMax的内容清空
  • 必须执行第二次滑动操作,才能彻底删除该行

核心原因

  1. 数据获取忽略未提交变更:DataController的liftEventsForSelectedFilter()方法中,给fetchRequest设置了includesPendingChanges = false,导致删除操作后立即查询时,无法获取到上下文的未提交删除变更,列表仍会展示已删除的条目(此时条目已变成fault状态,所以内容为空)。
  2. 视图无法监听数据变化:当前通过每次调用方法获取列表数据,而非使用@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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:30:53