Core Data 使用多个上下文中的新对象从后台线程订购一对多关系保存

Posted

技术标签:

【中文标题】Core Data 使用多个上下文中的新对象从后台线程订购一对多关系保存【英文标题】:Core Data ordered One-To-Many relation saving from background thread with new objects in multiple contexts 【发布时间】:2017-07-07 15:14:57 【问题描述】:

我在我的徒步旅行应用程序中使用 Core Data。对于轨迹中的坐标,我的数据中有一个有序的一对多关系。我使用后台线程来同步数据,并且我使用子NSManagedObjectContextNSPrivateQueueConcurrencyType 作为后台线程。尽我所能从关于核心数据和线程的 Apple 文档中得知,我已经正确设置了所有内容,以及如何在我的线程中使用 NSManagedObjectContext。这是我遇到的问题。

    在后台,同步过程会拉下轨迹的新坐标并更新子上下文中轨迹的坐标。 在主线程上,用户通过跟踪更多轨迹来更改轨迹。这些新坐标使用NSMainQueueConcurrencyType 保存到父上下文中。 所以现在主线程上下文有了新坐标,同步线程上下文有了新坐标。 然后同步线程保存其上下文并将坐标保存到父上下文。 然后主线程保存其上下文。保存主上下文上的新坐标并将它们添加到有序的一对多关系中。它们未保存在有序关系中的正确位置。 这会使路径“跳跃”。查看屏幕截图中的黑色轨迹。

这似乎 Core Data 正在做正确的事情。它不会删除任何新对象,它们都被添加到关系中。但是,在这种情况下,我只想从其中一个上下文中获取一组坐标,而不是将它们合并在一起。我找不到办法做到这一点。我现在解决这个问题的方法是将轨迹的对象 ID 和所有坐标传递给主线程并将它们保存在那里。我不想在主线程上做这项工作,这完全是 hack。有人知道更好的解决方案吗?

【问题讨论】:

我不确定我的 NSManagedObjectContext 配置是否正确。你能列出你的 NSManagedObjectContext 的父子节点以及并发类型吗? 【参考方案1】:

问题类别 在客户端和服务器之间同步对象的有序集合。

订单损坏 所描述的设置可能会导致coordinates 属性发生冲突。请考虑以下场景(表格代表坐标的有序集合):

子上下文开始同步。它获取 Track 及其坐标。结果,它看到与父上下文相同的有序集 家长:[c1, c2] 孩子:[c1, c2]

子上下文从服务器接收新坐标 家长:[c1, c2] 孩子:[c1, c2, c3]

父上下文接收一个新坐标 家长:[c1, c2, c4] 孩子:[c1, c2, c3]

如果您保存子上下文,坐标顺序是不明确的。 可以是[c1, c2, c3, c4][c1, c2, c4, c3],没有更多信息无法决定。

我已经测试了这个场景,不幸的是 Core Data 没有将这个报告为错误。它只是将来自子上下文的新对象附加到来自父上下文[c1, c2, c4, c3] 的坐标。

建议的解决方案 使用无序关系并扩展坐标实体以包含时间戳NSDate)。它将允许您对坐标进行排序。

使用NSFetchedResultsController 观察coordinates 之间的变化。它会告诉您何时添加新坐标以及在什么索引处。这应该提供足够的信息来重绘路径。

其他性能注意事项 此处描述的核心数据堆栈不是性能最高的选项。请参阅this article 了解更多信息。

【讨论】:

感谢您的帮助!!!这是最终成为我最终解决方案的灵感。对我来说,关键是自己处理订单并自己进行查询。我没有提供有关如何修改轨迹的所有详细信息,因此很遗憾时间戳不起作用。我最终在排序顺序的坐标中添加了一列。我还创建了坐标组。坐标有一个组 id,轨迹有组 id 用于查询的坐标集。

以上是关于Core Data 使用多个上下文中的新对象从后台线程订购一对多关系保存的主要内容,如果未能解决你的问题,请参考以下文章

在后台线程上安全保存 Core Data 托管对象上下文的正确方法?

Core Data,在后台线程中修改 NSManagedObject

从后台线程使用 Core Data 托管上下文......你如何正确地做到这一点?

如果您想通过 Core Data 使用多个实体,您需要为每个实体提供一个托管对象上下文吗?

当应用程序后台运行时,Core Data 无法通过区域监控保存上下文

Core Data 后台处理,保存不推送到主上下文