【问题标题】:EXC_BAD_ACCESS on mergeChangesFromContextDidSaveNotificationmergeChangesFromContextDidSaveNotification 上的 EXC_BAD_ACCESS
【发布时间】:2015-03-13 06:30:37
【问题描述】:

我们一直在尝试调试 Core Data 多上下文/线程问题,其中将 Core Data 保存通知合并到我们的主线程 NSManagedObjectContext 偶尔会导致应用程序崩溃。这导致我们大约 2% 的应用程序会话崩溃,我们不知道如何解决这个问题。对于可能导致此崩溃的原因,我们非常感谢任何指导或一般性建议。

我们有一个如下所示的核心数据设置:

注意这是 Magical Record v2.3 中从 [MagicalRecord setupAutoMigratingCoreDataStack] 创建的默认核心数据堆栈

这是我们的应用程序崩溃的场景:

  1. HTTP 请求返回 JSON
  2. JSON 在 Root Saving Context 上被解析为 NSManagedObjects(一些新实体,一些更新实体)
  3. 根保存上下文保存到持久存储
  4. NSManagedObjectContextDidSaveNotification 由 Core Data 广播。主队列上的默认上下文会观察到这一点,并在主线程上使用 NSDictionary 更改调用 mergeChangesFromContextDidSaveNotification:
  5. objectID 被发送到一个无效对象(很可能NSManagedObject 已被释放)时,它会崩溃。

这发生在 NSManagedObjectContext mergeChangesFromContextDidSaveNotification: 的私有实现中,所以我们不可能看到这里实际出了什么问题;在这一点上,我们只能说应该存在的对象不存在。

这只发生在一小部分 Core Data 保存中,这表明这可能不是我们的 Core Data → API 堆栈中的根本缺陷。此外,没有迹象表明上下文更改(插入/更新/删除)的大小或类型对崩溃的可能性有任何影响。

【问题讨论】:

  • 这些 MOC 使用什么类型的并发?合并更改时您使用的是performBlock: 还是performBlockAndWait:
  • 默认 MoC 使用主队列并发类型,Root Saving MoC 使用私有队列并发类型。与应用程序中的任何私有队列的任何交互都使用 performBlock 或 performBlockAndWait。根据 Apple 文档,我们不会通过执行块与默认上下文进行交互,但是我们会确保当我们不在主线程上时我们永远不会与它进行交互。
  • 只是我的 2ct;我在按本书做所有事情时遇到过这样的问题,它是由NSNotification 对象(或其userInfo 属性)的NSLog() 引起的。从那以后,我只在上下文中立即执行mergeChangesFromContextDidSaveNotification:,然后是save,而不以任何其他方式接触通知。从那以后,我再也没有见过它的段错误。
  • 鉴于根 MOC 位于私有队列上,是否还有其他线程的堆栈跟踪信息?它试图引用的对象是否可能是已在子 MOC 中删除(或以其他方式删除)的对象?

标签: ios objective-c core-data nsmanagedobjectcontext magicalrecord


【解决方案1】:

NSManagedObjectContextDidSaveNotification 的文档说:

"您可以在另一个线程上将通知对象传递给mergeChangesFromContextDidSaveNotification:,但是您不能直接在另一个线程上使用用户信息字典中的托管对象。有关更多详细信息,请参阅Core Data Programming Guide中的Concurrency with Core Data 。”

也许这就是问题所在?我会确保你从通知中获得的对象被保存在它由 Root 发布的同一线程上的默认上下文中。

【讨论】:

  • 这正是我的问题。我忘了通过在 ManagedObjectContext 上调用 performBlock 进行调度。
【解决方案2】:

一种可能性是您的持久存储已损坏并且处于不一致的状态。如果发生这种情况,会生成一个错误代码,Magical Record 不一定要处理。这可能是许多与 Magical Record 相关的难以重复的明显随机崩溃的根源(并且可能会或可能不会被视为 Magical Record 错误)。

值得阅读 Magical Record 问题线程here(相同问题)和here(不同问题,但可能是类似的原因)。当我遇到这些问题时,我设法按照这些线程中的各种提示进行了一些临时补丁修复,但最终我决定删除对 Magical Record 的依赖,从那时起我没有遇到任何问题。

【讨论】:

    【解决方案3】:

    自从这个问题发布以来已经有一段时间了,在重新发现它之后,我想回答我自己的问题,以便其他找到这个帖子的人。

    在我的情况下,我从兄弟NSManagedObjectContexts 迁移了一个大型代码库,通过NSManagedObjectContextDidSaveNotification 更新。然而问题与此无关,即使这确实暴露了问题。

    造成这种情况的真正原因是代码的旧部分由以前的工程师设置,在NSManagedObjects 及其属性上设置了 KVO。事实证明,Core Data 实体上的 KVO 实际上是一个非常非常糟糕的主意。

    更准确地说,这似乎是在实体上设置 KVO 并且对象或该对象上的关系目标从 NSPersistentStore 中删除时发生的。这第二种情况似乎不是问题的唯一原因,但在我的情况下绝对是一个非常突出的原因。

    经验教训:

    1. 在需要时使用获取的结果控制器。 KVO 不是一个方便的捷径,您不应避免将狡猾的 Core Data KVO 代码迁移到 NSFetchedResultsControllers 或其他明智的替代方案,因为拖延只会伤害您。
    2. 多线程 Core Data 是一项困难但非常值得成为专家的技能。了解您的 Core Data 堆栈以及 Core Data 多线程的细微差别和限制绝对值得所有精神痛苦。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-18
      • 2013-07-08
      • 2016-06-23
      • 2012-03-05
      • 2021-04-02
      • 2016-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多