Ios 使用核心数据和集成消除近重复项(iCloud) 总结

Ios 使用核心数据和集成消除近重复项(iCloud) 总结,ios,core-data,synchronization,icloud,ensembles,Ios,Core Data,Synchronization,Icloud,Ensembles,我的问题是,我想在用于与iCloud同步的基于核心数据的iOS项目中消除几乎重复的内容 与iCloud的同步在我的应用程序中基本上运行良好 问题在于,当一个用户在多个设备上创建相似的对象时,他的持久存储被集成(连接到iCloud)占用了 这会生成事实上正确的近似副本 我删除这些重复项的方法似乎不起作用 详细问题 在连接到iCloud之前,用户可以在不同的设备上创建NSManagedObjects。假设他有一个名为NSManagedObject的Car与名为Person的NSManagedOb

我的问题是,我想在用于与iCloud同步的基于核心数据的iOS项目中消除几乎重复的内容

  • 与iCloud的同步在我的应用程序中基本上运行良好
  • 问题在于,当一个用户在多个设备上创建相似的对象时,他的持久存储被集成(连接到iCloud)占用了
  • 这会生成事实上正确的近似副本
  • 我删除这些重复项的方法似乎不起作用
详细问题 在连接到iCloud之前,用户可以在不同的设备上创建
NSManagedObjects
。假设他有一个名为
NSManagedObject
Car
与名为
Person
NSManagedObject
有一个“对一”关系,反过来又与
Car
有一个“对多”关系。这看起来像这样:

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

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

这实际上是正确的,因为当用户使用持久性存储时,对象会获得其唯一标识符(用于标识集合中的对象)。这些对象实际上是不同的。但这正是我想要解决的问题

我的方法 我实现了这个委托方法,并删除了上下文中的重复项

- (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;
}
基本上,这在合并第一台设备数据的第二台设备上运行良好。但不幸的是,本地人似乎仍然同步到iCloud,即使它在上下文中被删除

这会导致断开状态,因为第一个设备也会合并来自第二个设备的更改,并再次替换已在第二个设备上删除的人员。一些同步之后,该人最终在汽车关系中失踪,应用程序抛出同步错误

重现问题的步骤
  • 步骤1(设备1)

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

    • 创建对象
    • 数据:汽车“宝马”->人“拉斐尔(装置2)”
  • 步骤3(设备1)

    • 从存储中提取数据
    • 连接到iCloud
    • 向iCloud发送数据
    • 数据:汽车“奥迪”->人“拉斐尔(装置1)”
  • 步骤4(设备2)

    • 从存储中提取数据
    • 连接到iCloud
    • 从iCloud合并数据
    • 将设备2的本地人员替换为设备1的插入人员
    • 从设备2中删除本地人
    • 向iCloud发送数据
    • 数据:
      汽车“奥迪”->人“拉斐尔(装置1)”
      汽车“宝马”->人“拉斐尔(装置1)”
  • 步骤5(设备1)

    • 从iCloud合并数据
    • 将设备1中的本地人员替换为设备2中插入的人员(不应发生这种情况)
    • 从设备1中删除本地人员(不应发生这种情况)
    • 向iCloud发送数据
    • 预期数据:
      汽车“奥迪”->人“拉斐尔(装置1)”
      汽车“宝马”->人“拉斐尔(装置1)”
    • 实际数据:
      汽车“奥迪”->人“拉斐尔(装置2)”
      汽车“宝马”->人“拉斐尔(装置2)”
实际上,本地person对象“Raphael(设备2)”在步骤4中被删除,但它似乎仍被发送到iCloud,因为在步骤5中,它在
savingContext中作为插入弹出。insertedObjects
来自
应保存合并更改ManagedObjectContext
委托方法

据我所知,Ensembles首先从iCloud中提取更改,通过委托方法询问用户是否一切都如预期的那样,然后合并到持久存储中,并在合并后向iCloud发送增量


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

我认为“修复上下文”处理程序的错误在于删除本地对象,保留远程对象。另一个设备也会这样做,但在这一边,反之亦然,然后删除错误的对象。修复方法必须是确定性的。所以,也许你可以按uniqueID或其他什么对这两个人进行排序,并总是删除第一个。然后所有的设备都会做同样的事情,不应该有乒乓同步把删除的数据带回来。

这就是lars提到的问题。你必须小心,总是果断地做事。按唯一id排序是一种方法

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

  • 在合并完成后执行重复数据消除(再次确保它是确定性的)
  • 使用精心选择的全局标识符为您控制重复数据消除 例如,您可以使用唯一的id
    Raphael
    。然后,您需要注意的唯一一件事是,当您在同一台机器上创建另一个Raphael时,它被称为
    Raphael_1
    (或其他)


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

    这是一个很好的观点!如果我有一个时间戳,我总是可以用最老的。但是使用唯一的ID并不能保证方法是确定性的,对吗?如果第三个设备加入并具有唯一的