【问题标题】:Core Data crash when trying to nullify relationship to deleted entity尝试取消与已删除实体的关系时,Core Data 崩溃
【发布时间】:2013-02-25 16:09:26
【问题描述】:

框架讨论:

  • 两个托管对象实体,A 和 B
  • A 和 B 之间存在一对一的反向关系
  • 关系的两个方向都有一个无效删除规则

问题:一段时间后,我正在通过实体 A 的实例进行编组,并尝试将关系更改为 newB(一段时间后与 oldB 建立了关系)(例如 A.B = newB),我得到了核心数据异常:

CoreData 无法满足“0x1e1515a0 x-coredata://90361082-A433-41A0-9F4E-BA3F032B193D/oldB/p7”的错误

根据我的研究和测试,我收到此错误是因为引用的 oldB 实体已删除并且不再可用于核心数据。 (我相信)抛出异常是因为 Core Data 试图访问 oldB 以使与 A 的关系无效,但显然不能,因为 oldB 已经消失了。

我不明白我是如何/为什么进入这种状态的,因为当我(在代码执行之前的某个时间)执行 removeObject: oldB 时,Core Data 应该已经无效这种关系,所以当我执行上述操作时,我希望 A.B == nil 已经。

我会说,这似乎在绝大多数时间都正常工作。但是,当这种情况发生时,应用程序将完全无法使用,直到数据库被删除/恢复。


所以,我希望回答几个问题:

  • 为什么会发生这种情况?这是否可能是开发工作的结果(例如,可能在 removeObject:oldB 完成之前终止进程等)在生产中不一定会发生?
  • 我有哪些恢复选项?我想我可以使用@try 和@catch 异常处理程序,但我不确定这最终是否会有所不同,因为@catch 处理程序会发生同样的问题,除非我有一些核心数据技巧不知道要“强制终止”这种关系(我认为这不会存在,因为它会在技术上破坏数据图)。
  • 就我的数据图而言,A 和 B 之间的关系是“松散的”,并不重要(事实上,B 对象在完成工作后会被删除)。因为我有一个独立于 A 的 B 清理过程,我是否最好只使用“无操作”删除策略,这样 Core Data 就不会在这些罕见的情况下阻塞?

感谢您提前提供的任何见解!


更新:

我一直在玩一些@try 和@catch 块。这是我发现的:

@try {
 if (A.B.A) // Relationship check. Will throw exception if B is missing
  nil;
 }
@catch {
 [moc deleteObject:A.B];
 [moc save:nil];
 }

在上述情况下,@catch 代码运行,但在保存时,Core Data 会抛出一个注解:

注释:修复对象 A 上一对一关系 B 的缺失删除传播

然后我尝试继续我的代码,当我再次尝试更改 A.B 时,我又回到了错误异常开始的地方。

所以,我尝试将@catch 块更改为:

@catch {
 [moc deleteObject:A.B];
 A.B = nil;
 [moc save:nil];
}

有趣的是,deleteObject 和设置 A.B = nil 有效,但是在保存时,会抛出原始异常:

CoreData 无法完成 '0x2009b1e0 x-coredata://90361082-A433-41A0-9F4E-BA3F032B193D/B/p10' 的错误

因此,在这种情况下,我似乎无能为力,因为 Core Data 不惜一切代价维护对象图(包括运行应用程序的能力!)。

没有重新初始化整个数据存储,有什么建议吗?

【问题讨论】:

  • A 的实体是否具有与 B 的关系的自定义设置器?您是否在任何地方观察到这种关系?
  • 不,我对 getter/setter 使用标准的 NSManagedObject @dynamic 属性。我的任何代码都不会通过 KVO 监控这种关系。
  • 我不确定发生了什么,但 FWIW,删除 B 不会使 A.B == nil 直到您保存更改。在那之前它仍然指向旧的 B。
  • @TomHarrington 那么,如果我的视图取决于我的模型并且如果删除一个实体,我是否必须保存?我以为我可以让用户在他想要的时候保存,但由于这条规则(删除不会在保存之前无效),我的模型是不连贯的。
  • 我已就此事向相关主题开放:stackoverflow.com/questions/17158091/…

标签: ios objective-c core-data


【解决方案1】:

我能够通过删除 catch 块中的 A 和 B 来解决此问题:

@try {
 if (A.B.A) // Relationship check. Will throw exception if B is missing
  nil;
 }
@catch {
 [moc deleteObject:A.B];
 [moc deleteObject:A];
 [moc save:nil];
 }

但是,这并不理想,因为 A 很重要(B 不重要)。幸运的是,可以以远低于丢失整个对象图的成本来重新生成 A。为了生产代码的工作,我认为这个解决方案是合适的,但并不理想。

仍然会喜欢一个允许保存实体 A 的答案...

【讨论】:

  • 我要补充一点,我在后台 MOC 上执行这项工作,我最终发现了一些罕见的实例,其中一个 NSManagedObject 在 MOC 之间传递,这是一个很大的 NoNo。我已经修补了它(使用 objectIDs)并更好地管理我的保存,所以我不再有这些故障问题。我想这个故事的寓意是,每当你遇到这样的错误时,绝对 1000% 确保你没有违反任何线程限制问题(例如,通过 NSLog 条目和跟踪 NSThread 值),因为这是每个问题的根源我的核心数据噩梦之一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多