核心数据上下文合并(已在子上下文中创建的对象)

时间:2019-02-27 08:40:24

标签: ios core-data nsmanagedobject nsmanagedobjectcontext

我拥有带有持久容器的Main上下文,Persistent Edit Context(Main上下文的子级)和Private Sync Context,用于长时间同步。

然后我在Edit Context中创建并创建对象->将其保存到Main Context->将这些更改发送到服务器->从服务器接收更新的更改->更新编辑上下文

我用

context.automaticallyMergesChangesFromParent = true

但是我也尝试过手动合并。

@objc private func contextSave(_ notification: Notification) {
        let updated = (notification.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject>)?
            .filter { $0 as? Order != nil }
            .map { $0 as! Order }

        updated?.forEach { order in
            Logger.shared.log("UPDATED FROM NOTIFICATION \n\n----\n\(order.objectID) \(order)\n-----\n\n")
        }

        localManagedContext.performAndWait {
            let orders = self.fetchInChildContext()
            orders.forEach {
                Logger.shared.log("LOCAL AFTER NOTIFICATION \n\n----\n\($0.objectID) \($0)\n-----\n\n")
            }
        }
    }

结果:我在编辑上下文中创建并从同步过程更新的对象即使在主上下文中更新并且位于NSUpdatedObjects集中,也没有更新。

所有其他对象已正确合并。并且从主上下文中获取对象时(而不是在子队列中创建对象时)。

这是“编辑上下文”中的对象

Optional(<BestatterprogrammI.Order: 0x600003f05720> (entity: Order; id: 0x600001cbefc0 <x-coredata:///Order/tBADA027E-D83F-4E34-A741-2EACD7877EE82> ; data: {

这是我在NSUpdatedObjects内部接收的对象

0xa8dc7e0d815e4391 <x-coredata://57464ABC-24B6-4E34-A992-3B2886E13686/Order/p2361> <BestatterprogrammI.Order: 0x600003ffec10> (entity: Order; id: 0xa8dc7e0d815e4391 <x-coredata://57464ABC-24B6-4E34-A992-3B2886E13686/Order/p2361> ; data: {

我要相应地保存“编辑上下文”和“同步上下文”:      //编辑上下文(主队列)      localManagedContext.performAndWait {             self.repopulateEntitiesID()

        do {
            if self.localManagedContext.hasChanges {
                try self.localManagedContext.save()

                if saveParent {
                    // using .parent on context results
                    // in unexpected behaviour on iOS 10
                    try CoreDataHandler.shared.persistentContainer.viewContext.save()
                }

                callback(.valid)
            } else {
                callback(.valid)
            }
        }


  // SYNC context (private queue)
  if context.hasChanges {
        do {
            try context.save()
        } catch let error {
            Logger.shared.logConsole(error)
        }
                   CoreDataHandler.shared.persistentContainer.viewContext.performAndWait {
            if CoreDataHandler.shared.persistentContainer.viewContext.hasChanges {
                do {
                    try CoreDataHandler.shared.persistentContainer.viewContext.save()
                    self.onSyncEventRaised.forEach { $0.value() }
                } catch let error {
                    Logger.shared.logConsole(error)
                }
            }
        }
    }

请指出一个错误,以及如何使上下文保持最新(不更改上下文)。

刷新对象会导致意外的行为,这些对象在上下文中重复。

我想要的是在“编辑上下文”中更新创建的对象,并允许用户进一步对其进行编辑。 预先感谢。

UPD: 创建同步上下文(临时):

 let syncContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
 syncContext.parent = CoreDataHandler.shared.persistentContainer.viewContext
 syncContext.perform {

创建编辑上下文(永久):

let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
context.parent = CoreDataHandler.shared.persistentContainer.viewContext
context.retainsRegisteredObjects = true
context.automaticallyMergesChangesFromParent = true

1 个答案:

答案 0 :(得分:0)

受以下因素影响:Core Data: Do child contexts ever get permanent objectIDs for newly inserted objects?

这里出现了相同的问题:Core Data merge two Managed Object Context

基本上我拥有的-在“编辑”上下文中创建的对象具有TEMPORARY ID,但是在“主要上下文”中创建的对象具有永久ID。

因此Core Data认为这是两个不同的对象,因此不会合并。 解决方案-在保存之前为插入的对象提供一个永久ID。

 localManagedContext.performAndWait {
        self.repopulateEntitiesID()

        do {
            if self.localManagedContext.hasChanges {
                // all inserted objects must get permanent ID to be updated
                // from other contexts before fetching it from persistent store directly

                let insertedObjects = Array(self.localManagedContext.insertedObjects)
                try self.localManagedContext.obtainPermanentIDs(for: insertedObjects)
                try self.localManagedContext.save()

                if saveParent {
                    try CoreDataHandler.shared.persistentContainer.viewContext.save()
                }

                callback(.valid)
            } else {
                callback(.valid)
            }
        }
        catch let error {
            Logger.shared.logConsole(error)
            callback(.error)
        }
    }