【问题标题】:Does a Core Data parent ManagedObjectContext need to share a concurrency type with the child context?Core Data 父 ManagedObjectContext 是否需要与子上下文共享并发类型?
【发布时间】:2012-01-15 11:37:51
【问题描述】:

我可以将 ManagedObjectContext 的父上下文设置为具有不同并发类型的 ManagedObjectContext 吗?例如:

backgroundManagedObjectContext_ = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[backgroundManagedObjectContext_ setPersistentStoreCoordinator:coordinator];
managedObjectContext_ = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[managedObjectContext_ setParentContext:backgroundManagedObjectContext_];

我的目标是(希望)为 managedObjectContext_ 快速保存(因为它只需要将内容保存到父内存上下文中),然后让 backgroundManagedObjectContext_ 在它自己的队列上进行保存。除非我碰巧需要在后台保存之前从“前台”队列中进行另一次保存,否则我的用户应该永远不会看到很长的保存时间。

我遇到了看起来像死锁的情况,但我不确定它们是否与此有关,或者我的问题是否在其他地方。


我可以或多或少可靠地产生死锁的地方的详细信息:

我有一个用于主线程的托管对象上下文,它由具有私有队列并发类型的托管对象上下文支持,并且具有持久存储。

我有几个实体类型(大约 5 个),每个实体类型都有一个或两个与另一个实体的双向关系。

我的应用想要使用 iCloud(我为这些测试拨了那个代码),所以它不能附带预先填充的数据库,它需要在检测到空数据库时构建它。

所以当我看到一个空数据库(在主线程上检查)时,我添加了大约 4 或 8 个实体类型,但其中一种实体类型除外,最后一个得到大约 100 个(所有添加都发生在主线程上)线)。主线程执行 saveContext。完成后(没有错误),它要求其他托管对象上下文运行一个也执行 saveContext 的块。这个 saveContext 绝对是一个死锁参与者。这也是唯一使用“背景”NSManagedObjectContext 完成的事情。

在此之后,确切的控制流有点模糊,因为 NSFetchedResultsController(所有给定的实体类型(有大约 3 个成员)都具有简单的排序,批量大小为 20 左右)驱动下一轮核心数据活动,但是来自 TableViewController 的调用询问它需要管理多少项目,即“获取的结果控制器有多少结果”。这个电话是僵局的另一面。 (所有这些都在主线程中)

【问题讨论】:

  • 为了命名约定,我建议您删除代码中的“_”后缀。将上下文命名为 childContext/parentContextchild/parent

标签: ios core-data


【解决方案1】:

根据我的经验,只要两个上下文都实现NSMainQueueConcurrencyTypeNSPrivateQueueConcurrencyType,这不是必需的。要记住的重要一点是,当跨多个线程与托管对象上下文交互时,发送到上下文的所有消息都必须通过-performBlock:performBlockAndWait: 发送。

在最近的一个项目中,我有一个父 NSManagedObjectContext 支持使用 NSMainQueueConcurrencyType 创建的 NSFetchedResultsController。从那里我创建了一个带有NSPrivateQueueConcurrencyTypeNSManagedObjectContext,并将上下文设置为NSMainQueueConcurrencyType 作为父级。现在,当添加一个新对象时,我的子上下文可能包含可丢弃的编辑,该对象最终会出现在由父上下文支持的 NSFetchedResultsController 支持的表视图中。当我准备好保存我的编辑并将它们冒泡到父上下文时,代码看起来像这样。

// Save the child context first
[childContext performBlock:^{
    NSError *error = nil;
    [childContext save:&error];

    // Save the changes on the main context
    [parentContext performBlock:^{
        NSError *parentError = nil;
        [parentContext save:&parentError];
    }];
}];

现在我不能肯定地说这是正确的方法,因为目前关于此的文档非常稀少。如果您可以显示一些您认为会导致死锁的代码,这可能会有所帮助。如果您在开发者计划中,您可能想查看今年有关 Core Data 的 WWDC 会议视频。我相信有两种,一种用于 Mac OS X,一种用于 iOS,它们基本上涉及相同的想法,但每个都包含独特的信息。

【讨论】:

  • 最佳和唯一的答案,时钟还剩一小时。我给你50分! (我已经看过两个 WWDC 视频中的一个,现在我知道另一个有一些独特的信息,我也会给它一个手表)。
  • 我认为唯一的区别是 Stripes 使父上下文由私有队列支持,而子上下文由主队列支持。然而@Mark 你却反其道而行之。我认为这会导致僵局与否。 Apple 似乎在 WWDC 2012 session 214 中支持 Stripes 的方式。
  • 只要不使用旧的线程限制模型,父或子的上下文类型无关紧要。更有可能是 OP 有两个 -performBlockAndWait:s 互相等待。
猜你喜欢
  • 2018-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-25
  • 1970-01-01
  • 2013-04-12
相关资源
最近更新 更多