尝试访问托管对象属性时的 EXC_BAD_ACCESS

Posted

技术标签:

【中文标题】尝试访问托管对象属性时的 EXC_BAD_ACCESS【英文标题】:EXC_BAD_ACCESS when trying to access a managed object property 【发布时间】:2013-03-17 19:48:02 【问题描述】:

我在处理核心数据+并发/嵌套 MOC 时遇到了一些问题(不确定我在使用 =P 时遇到了哪一个问题)。

我有一个方法,我传入一个托管对象 ID(我检查了它是否是永久的),并且该方法有一个子托管对象上下文,该上下文被限制在某个队列中。我可以通过[managedObjectContext objectWithID:moID] 从子托管对象上下文中检索对象,但是当我尝试访问它的任何属性时(托管对象仍然是一个错误),我得到EXC_BAD_ACCESS,堆栈跟踪显示_svfk_1 和@ 987654324@.

我知道在没有示例代码的情况下很难找出问题所在,但我希望有人能阐明可能的原因。谢谢。 =)

编辑:我尝试使用 existingObjectWithID:error: 而不是 Tom Harrington 建议的 objectWithID:,现在它有时有效,但有时无效。我还在mergeChangesFromContextDidSaveNotification: 上经历了EXC_BAD_ACCESS 崩溃。我怀疑这可能是一个同步问题。如果我在一个上下文中编辑某些内容并保存,而在我的子上下文中编辑其他内容,这会导致问题吗?

编辑 2: 我弄清楚了为什么 existingObjectWithID:error: 有时但并非总是有效。托管对象 ID 确实是一个临时 ID(不应该 mergeChangesFromContextDidSaveNotification: 将其转换为永久 ID 吗?),所以我必须在传递 ID 之前调用 obtainPermanentIDsForObjects:error:。但有时在子上下文的mergeChangesFromContextDidSaveNotification: 中我仍然会崩溃。这可能是什么原因?谢谢。

编辑 3:这是我的 MOC 层次结构的样子。

   Persistent Store Coordinator
                |
      Persistent Store MOC
         /            \
Main Queue MOC   Child MOC (confinement)

我正在从主队列调用一个方法,该方法使用子 MOC(在另一个队列中)插入和更新一些托管对象,同时,我正在持久存储 MOC 中插入和更新托管对象。托管对象也可以同时更新、删除和插入到主队列 MOC 中。我将 Persistent Store Coordinator 的任何更改合并到主队列 MOC 和子 MOC。

还有一些问题:保存 MOC 会自动合并事物吗?如果 MOC 有待处理的合并请求,并且您在处理该合并请求之前保存,这会导致问题吗?

编辑 4:这是我初始化子 MOC 的方式。

dispatch_sync(_searchQueue, ^
    _searchManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];

    [_searchManagedObjectContext setParentContext:_persistentStoreManagedObjectContext];
    [_searchManagedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
);

顺便说一句,我注意到只有当通知包含已删除的对象时,合并才会崩溃(EXC_BAD_ACCESS)。

【问题讨论】:

哦:“假设objectID表示的持久存储中的数据存在—如果不存在,则返回的对象在您访问任何属性时(即触发故障时)会抛出异常)。”让我检查一下。 不,我在托管对象子类的prepareForDeletion 中添加了一个断点,但它从未被触发。所以我调用这个方法的时候,被管理的对象并没有被删除。 您是否使用 performBlock 与子 MOC 对话(我假设它不在主队列中)? 子 MOC 被限制在一个串行队列中,我使用该队列上的子 MOC 执行所有操作。 尝试用existingObjectWithID:error:替换objectWithID:,看看会发生什么。 【参考方案1】:

看来你还是太努力了。对于您的子 MOC,由于它位于串行队列中,因此请使用 NSPrivateQueueConcurrencyType,并将其父 MOC 设置为您的主 MOC。

NSConfinementConcurrencyType 用于旧版配置。

【讨论】:

【参考方案2】:

我找到了解决办法。在每次保存之前,我都会做[moc obtainPermanentIDsForObjects:[[moc insertedObjects] allObjects] error:&error]。现在我不再遇到崩溃了。

我仍然对到底发生了什么有点模糊,但这是我的理解。当您保存新插入的对象时,只有在连接到持久存储协调器的 MOC 保存时,才会为它们分配一个永久 ID。现在,mergeChangesFromContextDidSaveNotification: 将永久 ID 向下传播(正如我所料),而其他一些操作恰好在合并之前发生,或者某处存在 Apple 错误。无论如何,事先获得永久 ID 解决了这个问题。

TL;DR Core Data+并发难。

【讨论】:

以上是关于尝试访问托管对象属性时的 EXC_BAD_ACCESS的主要内容,如果未能解决你的问题,请参考以下文章

释放对象时的奇怪行为

Swift Core Data - 使用 NSManagedObject 子类访问获取的实体时出错

在 C# 4 中使用动态类型访问 javascript 对象的属性

在 Core Data 中加载具有关系的托管对象时的标准行为是啥?

使用 COM 互操作从非托管 C++ 访问 c# 属性

在核心数据中保存到托管对象上下文时的 SIGABRT