【问题标题】:Merge NSManagedObject with equal properties, but different IDs, synced with iCloud results in duplicates (Core Data, Swift 1.2)合并具有相同属性但 ID 不同的 NSManagedObject,与 iCloud 同步会导致重复(Core Data,Swift 1.2)
【发布时间】:2015-04-14 10:56:08
【问题描述】:

我有一个使用 Core Data 和 iCloud 同步的 Swift 1.2 应用程序。

在第一个屏幕中,用户可以插入一些数据来创建自定义的 MyNSManagedObjects

每个 MyNSManagedObject 都必须有一个它所属的特定“组”。 这个“类别”在我的数据模型中由另一个自定义 NSManagedObject 表示,我们称之为 MyManagedObjectsCategory

用户可以创建许多 MyManagedObjectsCategory 对象,但应用还需要一个 MyManagedObjectsCategory 类型的 DEFAULT 对象,以防用户不创建任何不同的 MyManagedObjectsCategory

每个 MyNSManagedObjects 只能有 1 个 MyManagedObjectsCategory,但一个 MyManagedObjectsCategory 可以有多个 MyNSManagedObjects。

当用户启动应用程序时,我会立即检查 DEFAULT MyManagedObjectsCategory 是否已经存在,如果不存在,我会创建一个 DEFAULT MyManagedObjectsCategory 对象并将其保存到持久存储中。当然,只有在应用程序第一次启动时我需要创建这个对象,之后我总是会获取我在应用程序第一次启动时创建的对象并使用它。

我的问题是在我启用 iCloud 同步时开始的;现在,在应用程序首次启动时,会发生这种情况:

  1. 应用启动时按预期使用 STORAGE 1(本地),但未找到 MyManagedObjectsCategory 类型的 DEFAULT 对象,它创建了一个新对象。

  2. 如果有网络覆盖,几秒钟后应用程序切换到 STORAGE 0(云)并保存刚刚创建的 DEFAULT MyManagedObjectsCategory 对象;如果设备离线,这不会立即发生,但当然会在稍后网络连接可用时发生。

当我在不同的设备上第一次启动应用程序时,上面的第 1 点和第 2 点再次发生:由于应用程序从存储 1 开始,它不会获取 DEFAULT MyManagedObjectsCategory 对象它会创建并保存一个新的,几秒钟后或当网络可用时,当应用切换存储时,它会同步到存储 0。

您可以想象,当不同的设备同步时,我发现自己有多个 DEFAULT 对象,而且由于我是 Core Data 的新手,我不知道如何处理这个问题。

一方面,我需要在应用启动时立即使用 DEFAULT 对象,所以我迫不及待地切换到存储 0(另外,因为我不知道用户是否有网络连接,所以存储切换可能会在很久以后发生);另一方面,DEFAULT 对象的目的是在每个设备上都是一个,并且始终相同。

我了解,即使每个 DEFAULT 对象都具有以完全相同的方式创建的匹配属性(对象具有名称和 myID 字符串属性),Core Data 也会为每个托管对象创建一个唯一 ID,并且由于 ID在不同时刻在不同设备上创建的 DEFAULT 对象之间不匹配,它不会将它们合并到单个 DEFAULT 对象中。

所以,我的问题:

  • 如果某些属性完全相同,是否有办法强制将 DEFAULT 对象合并为一个对象?是这样,怎么做?我想我可以在应用启动时这样做,因为只有在将新设备添加到 iCloud 时才会发生 DEFAULT 对象的复制。

  • 是否有完全不同的方法来处理我所遗漏的这个问题?

我在过去的 2 个月里一直在开发这个应用程序,但是我无法在同步时发送重复对象的东西,而且我不知道如何修复它,所以任何帮助都非常非常感谢。

谢谢, @cdf1982

【问题讨论】:

  • 将 CodeData 与 ICloud 一起使用时,很难避免数据不同步。在我的公司,我们以这种方式制作了一款应用程序,我向您保证,我们永远不会再这样做了。系统的不透明性使得修复不同步数据变得非常困难。苹果对这个特定问题的支持一直非常……沉默。我对你的建议:不要将 CoreData 与 iCloud 一起使用,而且最重要的是不要相信那些告诉你它会产生奇迹的人,因为它不会。

标签: swift core-data sync icloud nsmanagedobject


【解决方案1】:

这是使用 iCloud 或任何同步机制的基础。如果您的应用在多个设备上创建了相同的实例,并且不能坐等查看它是否已经存在于不同的设备上,那么您将得到重复。

处理此问题的唯一方法是让重复发生,然后清理它们。使用 iCloud,您会在收到 NSPersistentStoreDidImportUbiquitousContentChangesNotification 时进行清理,这表明有新的传入数据可用。基本方案是进行提取以查找所有重复项,然后根据您的应用程序的需要(合并/删除/其他)处理它们。我在a previous answerin a blog post 中详细描述了这一点。

如果您的类别实体有一个存储唯一 ID 的属性,并且您确保始终为默认类别使用相同的唯一 ID 值,那么您自己会轻松很多实例。然后,您可以通过仅获取与已知唯一 ID 值匹配的对象来简化重复数据删除。

【讨论】:

  • 您好,感谢您的回答,特别感谢您,因为自从我在您的博客文章和我面前的 Apple 的 SharedCoreData WWDC 项目中发布了这个问题以来,我已经花了很多时间:我已经有一个唯一的 ID类别实体,并按照您的帖子和 Apple 的 deDupe 示例代码,我正在尝试按照您的建议进行操作。这对我来说有点困难,因为我实际上是在将 Objective C 代码翻译成 Swift,但是在离开我的电脑之前(我现在正在打电话,抱歉打错了)我能够将重复的内容记录到控制台,所以我假设我走上了一条好路……您的帖子很宝贵
  • ...现在让我们看看我是否能够完成任务(我不是编程专家)。如果我愿意,我会让你和每个人都知道,从相当古老的示例项目中发布我的 Apple 的 deDupe 方法的 Swift 版本......字典有一些棘手的部分,但我很乐观。再次感谢!
  • 早上好@TomHarrington,我想我已经成功地将 SharedCoreData 的 deDupe 方法从 Objective C 移植到了 Swift。在这里发布我的代码之前,如果可以的话,我还有一个问题:在合并更改后,我在persistentStoreDidImportUbiquitousContentChanges 中调用我的 deDeduplica 方法,但这意味着目前每次添加、更新对象时都会调用我的 deDuplicate 方法或删除,当然,这不是有效的。我看到你在博文中写道...
  • "传入的更改通知具有插入、更新和删除对象的单独列表。如果您过去扫描过重复项,您知道不会有任何新的重复项,除非至少插入了一个新对象。当只有更新和/或删除到达时跳过重复检测。” 遗憾的是,我不得不承认我不知道如何检查传入的更改通知,所以我不知道当只有更新和删除时,知道如何跳过对 deDuplicate() 的调用。我可以请您指出正确的方向,或者您是否有一些代码作为示例?谢谢!
  • 该通知的userInfo 字典具有名为NSInsertedObjectsKey NSUpdatedObjectsKey NSDeletedObjectsKey 的键,可用于检查已发生的更改。在这种情况下,你只关心NSInsertedObjectsKey
猜你喜欢
  • 1970-01-01
  • 2013-11-26
  • 2017-02-27
  • 2017-03-07
  • 1970-01-01
  • 2013-07-31
  • 2017-05-05
  • 2014-08-31
  • 1970-01-01
相关资源
最近更新 更多