【问题标题】:Core Data background sync conflict issueCore Data 后台同步冲突问题
【发布时间】:2010-06-28 14:49:07
【问题描述】:

我在使用 Core Data 开发 iPhone 应用程序时遇到了崩溃问题。

应用在后台线程上将数据与网络服务同步。

当应用首次启动时,Core Data DB 中的现有数据将在 UITableView 中显示给用户,同时启动后台线程从 Web 服务 API 中获取最新数据。让我们将核心数据模型称为用户和项目,只是为了与拥有许多项目的用户进行讨论。这些项目是 UITableView 中显示的内容。

当返回 API 结果时,用户现有的项目记录将从核心数据中删除,并将新的项目记录集插入核心数据。解析完所有项目后,会向主线程发送一条消息,以合并核心数据更改并从 CD 重新获取数据。

但是,我在配置表格单元例程中不断崩溃,我确信这是因为超出范围的对象。这意味着,主线程正在尝试显示 Core Data 中的对象,而后台线程正在从 Core Data 中删除相同的对象并用新对象替换它们。

处理此类冲突的最佳方法是什么?我是否必须采用某种机制才能在主视图加载/显示其所有数据之前不启动后台线程更新?如果是这样,我该如何做到这一点?我还能保持相同的方法并更好地处理显示项目的删除吗?

【问题讨论】:

  • 在我删除记录时,有没有办法锁定单个持久存储协调器?还是我应该使用单独的持久存储协调器?我不确定,只是在这里大声说出来,因为这是我第一次在应用程序中使用 Core Data。
  • 为什么 Item 实体被删除而不是与来自 web 服务调用的更新状态合并?
  • 它们被删除是因为我认为删除并重新插入更新的数据而不是尝试管理与项目的状态差异更容易。如果我只是尝试更新,我需要跟踪哪些属性已更改,然后更新这些属性,或者只是从 API 服务器完全重置项目。我最初的想法是,只进行批量删除/替换而不是从 API 解析对象、对 Core Data 进行一次查找,然后再进行一次更新操作会更容易
  • "尚未告知视图的 FRC 合并新更改。"你注册NSManagedObjectContextDidSaveNotifiction了吗?
  • @falconcreek,是的,我的应用程序委托注册了 NSManagedObjectContextDidSaveNotifiction,但没有注册 FRC 的视图控制器

标签: iphone uitableview core-data


【解决方案1】:

参考TopSongs项目SongsViewController实现 特别是viewDidLoadhandleSaveNotification

- (void)handleSaveNotification:(NSNotification *)aNotification {
[managedObjectContext mergeChangesFromContextDidSaveNotification:aNotification];
[self fetch];
}

您的 viewController 的 handleSaveNotification: 没有被调用,因为您注册了来自它拥有的 MOC 的通知,而不是所有 MOC。它适用于 TopSongs 示例,因为应用程序委托和 viewController 的 MOC 是同一个对象。 (appDelegate 将 moc 传递给 songViewController)。

替换:

// ViewController.m viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:self.managedObjectContext];

与:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:nil];

替换:

// ViewController.m viewDidUnload
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:self.managedObjectContext];

与:

[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:nil];

【讨论】:

  • 这实际上正是我正在做的。我对 Apple 的 TopSongs 示例项目的大部分后台更新代码进行了建模。
  • 可以在两个地方注册同一个通知,对吗?我在视图控制器和我的应用程序委托中注册此通知,就像 TopSongs 项目中的示例一样,如果我将日志消息放在两个回调中,我只能在我的应用程序委托中看到来自一个的日志消息,而不是那个在我的视图控制器中
  • 好的,这就是我阅读文档时的想法。不知道为什么这两种方法都没有收到相同的通知回调,即使它们都注册了它。只有 App 委托回调正在运行。
  • 与 TopSongs 演示的不同之处在于,它们只是彻底清除了持久存储,并在进行同步之前创建了一个新存储。我不能这样做,因为我有多个用户,所以我只能删除特定用户的 Item 对象,而不是每个人。另外,我还有其他不能被吹走的桌子。
  • 您必须发布代码,显示您如何注册通知和action 方法以确定为什么您的通知没有触发您的viewController handleSaveNotification:。收到通知时,您的应用程序代表在做什么?我不是建议你从一家新店开始。只需刷新您需要的实体。
【解决方案2】:

这些核心数据操作是否如此昂贵以至于您无法从主线程执行此操作?只需在另一个线程上执行 webservice 部分。否则,它可能会变得更加困难 - 可能会在两者之间放置一些控制器类来缓存相关数据或同步对 Core Data 的访问。

【讨论】:

  • 代价高昂的部分只是将数据传入和传出 API 服务器的潜在延迟。不想在上传或在这种情况下从 API 服务器下载更新数据时阻止 UI。核心数据操作本身并不重要,不。如果这是最佳解决方案,我想我可以重构我的工作并在主线程上执行实际的 CD 删除/插入方法
  • 是否有任何本地缓存解决方案,或者我必须推出自己的缓存控制器?
  • NSFetchedResultsController 以安全的方式将 Core Data 连接到 UITableView,它还可以在您对数据进行更改时对其进行处理。
【解决方案3】:

您如何访问表格的数据?如果您使用的是NSFetchedResultsController,它应该会以安全的方式自动更新单元格。

在您原始问题的范围内:
除非您的数据保存在其他地方,否则在滚动表格时重绘单元格会访问数据。你可以复制你用来填充单元格的所有数据,但这会增加你的内存使用量。

【讨论】:

  • 我正在使用 NSFetchedResultsController 在 UITableView 中显示数据。我认为 frc 为你管理了处理,但我的猜测是它试图同时显示数据,它在后台线程中被删除,并且由于单独的 managedObjectContexts 并且它没有被告知它不知道它被删除了尚未合并新的更改
【解决方案4】:

主线程和后台线程是否各自使用自己的 Core Data 托管对象上下文?您可能还想在

上查看 Core Data 多线程技巧

http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdMultiThreading.html

【讨论】:

  • 不,这两个线程使用单独的托管对象上下文,但使用一个持久存储协调器。顺便说一句,我正在审查这些文档。
【解决方案5】:

检查您的 NSFetchedResultsControllerDelegate 方法 controllerWillChangeContent:controllerDidChangeContent:

您有责任通过beginUpdatesendUpdates 消息通知表格您将对其进行更改。当获取的结果控制器要修改返回的数据时,表需要冻结更新自身,直到控制器完成。否则,表格会尝试表示不断变化的数据列表。

【讨论】:

  • 我觉得我有点困惑。您提到的那些方法是 FRC 委托协议的一部分,对吗?它们不是我目前手动调用的东西。我将如何从我的后台线程手动调用它们?或者这不是你的意思?
  • 你实现了委托方法。消息被发送到作为 FRC 实例委托的对象。这通常与管理 tableView 的控制器对象相同。
  • 正确。我确实在包含管理 UITableView 的 FRC 的视图控制器中实现了这些委托方法。我不明白的是,我的后台线程控制器与在后台线程上执行删除和更新有什么关系?这如何影响和/或在主线程上调用视图控制器上的 FRC 委托方法以防止删除崩溃问题?
  • 它们没有被调用,因为您的 FRC 不知道发生了更改,因为您尚未注册保存通知。
  • 查看我对您其他帖子的评论。我确实在包含我的 FRC 的视图控制器中注册通知
【解决方案6】:

你解决了吗?

检查您是否 a) 不使用缓存 - 即您最初创建 FRC 时的调用不使用缓存:

 NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil]

(见缓存名称:nil)

b) 你在 FRC 中使用谓词吗?我现在遇到了各种各样的问题,试图做和你的代码一样的事情。

【讨论】:

  • 不,我还没有找到解决方案,是的,我实际上正在使用缓存。我会在不缓存的情况下尝试它,看看它是否能解决我的问题。为什么缓存会导致所描述的错误?另外,我在我的 FRC 中使用谓词,是的。
猜你喜欢
  • 1970-01-01
  • 2019-10-19
  • 2022-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-14
  • 1970-01-01
相关资源
最近更新 更多