2

概括

我的问题是,我想在使用Ensembles与 iCloud 同步的基于 Core Data 的 iOS 项目中去除几乎重复的内容。

  • 与 iCloud 的同步在我的应用程序中运行良好。
  • 问题是当用户在他的持久存储被 Ensembles(连接到 iCloud)窃取之前在多个设备上创建类似的对象时。
  • 这会产生近乎重复的事实,这实际上是正确的。
  • 我删除这些重复项的方法似乎不起作用。

详细问题

用户可以NSManagedObjects在连接到 iCloud 之前在不同的设备上创建。假设他有一个NSManagedObject名称,该名称与一个名称Car具有“对一个”关系,而该名称与一个NSManagedObject名称Person具有“对多”关系Car。这看起来像这样: 简化模型

好的,假设用户有两个设备,他NSManagedObjects在每个设备上创建了两个。一个Car叫“奥迪”,一个Person叫“拉斐尔”。两者都是通过关系联系在一起的。在另一台设备上,他创建了一个Car名为“BMW”和另一个Person名为“Raphael”的设备。也相互连接。现在用户在每台设备上都有两个相似的对象:两个Person对象都名为“Raphael”。

我的问题是,用户在同步后最终会Person在每台设备上拥有两个名为“Raphael”的对象。

这实际上是正确的,因为当用户窃取他的持久存储时,对象会获得它们的唯一标识符(以识别 Ensembles 中的对象)。对象实际上是不同的。但这是我想要解决的。

我的方法

我实现了这个委托方法并删除了 reparationContext 中的重复项。

- (BOOL)persistentStoreEnsemble:(CDEPersistentStoreEnsemble *)ensemble 
    shouldSaveMergedChangesInManagedObjectContext:(NSManagedObjectContext*)savingContext
    reparationManagedObjectContext(NSManagedObjectContext *)reparationContext {

    [reparationContext performBlockAndWait:^{

        // Find duplicates
        // Change relationships and only use the inserted Person object (the one from iCloud)
        // Delete local Person object
        [reparationContext save:nil];
    }
    return YES;
}

基本上,这似乎在合并来自第一个设备的数据的第二个设备上运行良好。但不幸的是,即使在reparationContext中被删除,本地人似乎仍然同步到iCloud。

这会导致损坏状态,因为第一台设备随后还会合并来自第二台设备的更改并再次替换已在第二台设备上删除的人员。稍后进行一些同步,该人最终在汽车关系中丢失,并且应用程序引发同步错误。

重现问题的步骤

  • 第 1 步(设备 1)

    • 创建对象
    • 数据:汽车“奥迪”-> 人“拉斐尔(设备 1)”
  • 第 2 步(设备 2)

    • 创建对象
    • 数据:汽车“BMW”-> 人“Raphael(设备 2)”
  • 第 3 步(设备 1)

    • 来自商店的水蛭数据
    • 连接到 iCloud
    • 将数据发送到 iCloud
    • 数据:汽车“奥迪”-> 人“拉斐尔(设备 1)”
  • 第 4 步(设备 2)

    • 来自商店的水蛭数据
    • 连接到 iCloud
    • 合并来自 iCloud 的数据
    • 将设备 2 中的本地人员替换为设备 1 中的插入人员
    • 从设备 2 中删除本地人
    • 将数据发送到 iCloud
    • 数据:
      汽车“Audi” -> 人“Raphael(设备 1)”
      汽车“BMW” -> 人“Raphael(设备 1)”
  • 第 5 步(设备 1)

    • 合并来自 iCloud 的数据
    • 将设备 1 中的本地人员替换为设备 2 中的插入人员(这不应该发生)
    • 从设备 1 中删除本地人(这不应该发生)
    • 将数据发送到 iCloud
    • 预期数据:
      汽车“Audi” -> 人“Raphael(设备 1)”
      汽车“BMW” -> 人“Raphael(设备 1)”
    • 实际数据:
      汽车“Audi” -> 人物“Raphael(设备 2)”
      汽车“BMW” -> 人物“Raphael(设备 2)”

实际上,本地人员对象“Raphael (Device 2)”在第 4 步中被删除,但它似乎仍被发送到 iCloud,因为在第 5 步中它作为委托方法 savingContext.insertedObjects的插入弹出。shouldSaveMergedChangesInManagedObjectContext

据我了解,Ensembles 首先从 iCloud 中提取更改,通过委托方法询问用户是否一切都符合预期,然后合并到持久存储中,并在合并后将增量发送到 iCloud。

难道我做错了什么?或者这是一个集成错误?

4

2 回答 2

2

有 lars 提到的问题。您确实必须小心,始终确定性地做事。对唯一 ID 进行排序是一种方法。

就个人而言,我会以另外两种方式来处理这个:

  1. 合并完成后执行重复数据删除(再次确保它是确定性的)
  2. 使用精心挑选的全局标识符为您控制重复数据删除。

例如,您可以使用唯一 id Raphael。您唯一需要注意的是,当您在同一台机器上创建另一个 Raphael 时,它会被调用Raphael_1(或其他)。

如果您的唯一 ID 很可能是唯一的(例如名字 + 姓氏不太可能发生冲突),Ensembles 将自动合并不同设备上的人。

于 2016-01-25T12:29:32.000 回答
1

我认为您的“reparationContext”处理程序有问题,是您删除了本地对象并保留了远程对象。另一个设备会做同样的事情,但反之亦然,然后删除错误的对象。修复方法必须是确定性的。因此,也许您可​​以按 uniqueID 或其他内容对两个 Person 进行排序,并始终删除第一个。然后所有设备都会做同样的事情,并且不应该有乒乓同步将删除的数据带回来。

于 2016-01-25T08:54:34.293 回答