问题 调试NSObjectInaccessibleException - ID为0x123456789的NSManagedObject已失效


我有一个我正在努力追查的错误。我相信正在发生的事情是我从底层数据库中删除一个对象,而另一个托管对象上下文(在另一个线程中)有一个错误,并在尝试完成错误时获得'NSObjectInaccessibleException'。

场景是我有一个视图通过一个上下文同时在后台访问数据,另一个威胁是从商店中清除过时的记录。后台线程应该只清除视图不需要的对象 - 显然情况并非如此,但我无法准确地追踪到底发生了什么。当我看到缺陷时,为时已晚,这是一个相对罕见的缺陷,主要发生在现场。

因此我的问题是:在调试CoreData时是否有任何技巧缺失 - 我可以在另一个上下文中跟踪对象的生命周期吗?即当我删除我的对象时,有一种简单的方法可以查看是否有任何其他上下文引用了同一个对象?使用它,我可以构建一些测试代码来检查我的逻辑并找到错误。


9002
2017-08-09 07:24


起源

吉姆,你为什么放弃我的iPhone标签?我在iPhone上工作,所以我没有CoreData绑定。 - Rog
罗杰 - 我把iPhone标签放回去了。但这实际上是一个通用的核心数据问题,可能发生在桌面或移动平台上。 - Jim Correia
所以我已经诊断出这是一个iPhone问题,虽然可能发生在任何地方。 - Rog
Ben,为什么删除iPhone特定标签并添加可可触摸(iPhone特定标签)? - Rog


答案:


我之前遇到过这个错误,罪魁祸首是我正在清理(完成发布)我的上下文,然后尝试访问由该上下文管理的对象(以前)。

就我而言,上下文是一个“刮擦”上下文,在视图关闭时会消失。但是,我有一个后台工作,该视图产生了想要更新对象的后台工作。

我最终为[managedObject isFault]为true时返回nil的托管对象创建了一个访问器。然后在我的代码中,我检查了访问器选择器的值,以确保我有一个有效的对象(比如当我的后台作业最终完成它的工作)。

我对Core Data很陌生,所以可能有更好/更聪明的方法来做到这一点,但我认为它解决了我的问题。


7
2017-10-28 20:17



杰森,谢谢你重新引起我的注意。我最近修复了我的错误,它是清理和MapKit的组合 - 地图视图保持他们的委托太长。在您的情况下,您可能不应该从后台线程访问相同的NSMAnagedObject上下文 - CoreData不是线程安全的。相反,您应该将NSManagedObjectReference传递给后台任务。 - Rog
是的,你肯定是对的。在我的情况下,我在实际编辑对象之前跳回主线程(我创建所有上下文),但是当它的上下文再次出现时仍然没有好处。 - Jason
您所说的“NSManagedObjectReference”是什么?根据文件,不存在...... - Adam
他可能意味着 NSManagedObjectID秒。 - raheel


我也只是面对这个问题。我做了一些重构来追随Apple的 “发现 - 或创建” 批量导入数据的模式。我通过将undomanager设置为nil来创建一个专用于导入的新上下文。 所以:

// create a new special context for the bulk import of data
NSManagedObjectContext *importContext = [[NSManagedObjectContext alloc] init];
[importContext setPersistentStoreCoordinator:_persistentStoreCoordinator];

// avoid tracking for undo/redo operations
[importContext setUndoManager:nil];

然后我创建了一个fetchRequest来检索存储在数据库中的对象的id,并且在import循环中我测试了对象的id以查找它是否包含在检索到的id数组中...问题是在给定的时间间隔我正在保存importContext并重置它。因为我错误地引用了importContext而不是defaultContext,所以我得到了那个错误。我只是通过改变来修复:

NSArray *storedObjects = [importContext executeFetchRequest:checkRequest error:&fetchError];

有:

NSArray *storedObjects = [defaultContext executeFetchRequest:checkRequest error:&fetchError];

2
2017-07-06 12:05



对iOS用户来说只是一个侧面说明。在iOS上 undoManager 财产是 nil 默认。 - stigi


当它试图在从持久性存储中删除的对象中出错时,第二个上下文是做什么的?

这听起来像一个可能包含两部分的错误:你没有合并来自你的对等上下文的更改,并且你有一个逻辑错误导致你在线程B中使用了一个已经在线程A中删除的对象。

通常,您希望使用以下方式合并来自对等上下文的更改 -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:]


1
2017-08-11 00:55



我认为这里有两个错误,我同意它们是什么:-(我需要的是一种跟踪它们的方法。 - Rog
您是否正在合并来自同伴环境的更改?出于调试目的,您可以在保存上下文时记录已删除的对象。如果您知道所有其他现存的上下文是什么,您还可以检查使用这些上下文注册的对象,但您必须以线程安全的方式执行此操作。 - Jim Correia
你是对的。我决定我需要修复整个线程情况来解决这个缺陷。这不是微不足道的,但可能对我的健康有益。 - Rog


解决方案是清理和组合 这个mapkit错误。在我发布了NSManagedObjectContext之后,地图视图正在保持其委托。 Mapkit向代表询问了注释的坐标,我的委托对象试图查询处于已发布上下文中的对象(类似于Jason的问题)。

修复程序如Jake的博客文章中所述 - 当您完成地图视图时将委托设置为nil。


1
2017-10-31 08:18



链接坏了。你有新的,或者你可以解释一下吗? - bearMountain
我以为我做到了。问题是某些类对其委托持有弱引用,并在取消分配后向其发送消息。如果您看到此问题,请确保您在代表的任何类中都没有委托(或数据源)引用。 - Rog
谢谢你的澄清。 - bearMountain
这对我来说也是问题,在iOS 8.0上也是如此。在委托中,我正在访问我删除的托管对象。 - blkhp19