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

合并Core Data上下文后NSFetchedResultsController返回重复对象问题咨询

问题原因

这是Core Data上下文自动合并+临时ID转永久ID时序差触发的NSFetchedResultsController(下称FRC)已知异常,核心触发逻辑如下:

  1. 新增Item对象时,Core Data会先给对象分配临时ID,此时viewContext.processPendingChanges()会让绑定viewContext的FRC感知到新增对象,插入第一条记录。
  2. 保存viewContext时,变更推送到父上下文rootCtx,此时对象仍为临时ID,若FRC触发了第二次变更通知,会误判为新对象插入第二条记录。
  3. 保存rootCtx到持久化存储时,对象才会被分配永久ID,由于你给viewContext开启了automaticallyMergesChangesFromParent,rootCtx的变更会自动合并回viewContext,部分场景下会再次触发FRC的插入逻辑。
  4. 额外的无效配置加剧了问题:rootCtx直接绑定持久化存储协调器,没有父上下文,你给它开启automaticallyMergesChangesFromParent完全无意义,反而会引发不必要的变更通知。

解决方案

按优先级从高到低尝试以下方案:

  1. 新增对象保存前先获取永久ID,避免临时ID转永久ID的时序问题
func weirdTest() {
   print("1. Adding.")
   let item = Item(context: viewContext)
   item.id = UUID()
   // 新增这行,提前获取永久ID
   try! viewContext.obtainPermanentIDs(for: [item])
   viewContext.processPendingChanges()
     
   print("2. Saving.")
   viewContext.performAndWait {
      try! viewContext.save()
   }
   rootCtx.performAndWait {
      try! rootCtx.save()
   }
}
  1. 删除rootCtx的无效自动合并配置
lazy var rootCtx: NSManagedObjectContext = {
     let rootCtx = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
     rootCtx.persistentStoreCoordinator = coordinator
     // 移除该行无效配置
     // rootCtx.automaticallyMergesChangesFromParent = true
     return rootCtx
}()
  1. 若仍有异常,手动对FRC返回的结果去重
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
     let rawItems = (controller.fetchedObjects ?? []) as! [Item]
     // 按objectID去重,避免重复条目
     items = rawItems.reduce(into: []) { result, item in
         if !result.map({ $0.objectID }).contains(item.objectID) {
             result.append(item)
         }
     }
}

内容的提问来源于stack exchange,提问作者msmialko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 15:27:04