核心数据:-deleteObject:崩溃,删除规则是原因吗?

Posted

技术标签:

【中文标题】核心数据:-deleteObject:崩溃,删除规则是原因吗?【英文标题】:Core Data: -deleteObject: Crashes, Are Delete Rules the Cause? 【发布时间】:2010-02-24 11:50:34 【问题描述】:

我有以下型号,如图所示。

alt text http://img521.imageshack.us/img521/9741/schermata20100224a12251.png

我的应用程序需要刷新 B 的每个实例,因此在每个 viewWillAppear 处,我需要删除模型中的所有 B。删除 B 时,与 C 的关系的级联删除规则将删除所有 C,然后级联到所有 D。 A & E 是常数。

我对每个对象都有如下的 DeleteRule:

A: b - Cascade
B: c - Cascade, a - Nullify
C: b - Nullify, d - Cascade
D: c - Nullify, e - Nullify
E: d - Cascade

A -(cascade)->> B -(cascade)-> C -(cascade)->> D -(nullify)-> E
A <-(nullify)- B <-(nullify)- C <-(nullify)- D <-(nullify) E

我在级联所有 B、C、D 上的删除时遇到问题。我的 fetchRequest 对象返回 A 中 B 的每个实例,然后我从 managedObjectContext 调用每个 B 上的 -deleteObject:。但是在调用 [managedObjectContext save:&error] 时会出现 EXC_BAD_ACCESS。

谁能告诉我我做错了什么?我是否对每个实体的 DeleteRule 有问题,还是问题出在其他地方?处理对三个对象 B、C、D 的级联删除的最佳做法是什么?

已编辑:

这是引发错误时的堆栈跟踪:

  #0    0x01d843ae in ___forwarding___
  #1    0x01d606c2 in __forwarding_prep_0___
  #2    0x01c618b6 in -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:]
  #3    0x0003263a in _nsnote_callback
  #4    0x01d4f005 in _CFXNotificationPostNotification
  #5    0x0002fef0 in -[NSNotificationCenter postNotificationName:object:userInfo:]
  #6    0x01bc217d in -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:]
  #7    0x01c21763 in -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:]
  #8    0x01ba65ea in -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:]
  #9    0x01bdc728 in -[NSManagedObjectContext save:]

这是我尝试将 NSZombieEnabled 和 MallocStackLogging 设置为 YES 时控制台中的日志:

  2010-02-24 15:41:39.803 Foo[2591:207] deleting object: FUM5
  2010-02-24 15:41:40.515 Foo[2591:207] *** -[viewController controllerWillChangeContent:]: message sent to deallocated instance 0x7e54510

编辑 2:添加源代码

我试图通过创建一个具有图像中确切架构的新项目来重现这种情况。你可以download it from here。还有一个 README 文本。希望我提供了足够的信息。

【问题讨论】:

+1 非常好的问题!提供足够的细节。明确说明问题。你花了一些时间,我很感激。 【参考方案1】:

我认为问题可能在于 C 和 D 之间的必需关系。如果您将图表配置为:

    每个 C 至少需要一个 D。 C 的许多实例都指向同一个 D。

然后在某个时候,C 很可能会发现它所需的关系已被取消。如果它仍然尝试访问 D,那将触发 EXC_BAD_ACCESS。 (如果每个 E 需要一个 D,你可能会遇到同样的问题)

我建议调试,

将关系 C-->D 设置为可选,并查看错误是否消失。 从 C-->D 开始将级联更改为空值,然后查看错误是否消失。 如果您有类,请检查实例是否不共享实体图之外的某些共同对象。例如,C 类和 D 类都引用了同一个图像,但该图像不是实体的一部分。如果外部引用没有正确保留,也可能导致类似的崩溃。 在调用后立即将保存移动到删除每个 B。在删除之前记录每个 B 和 Cs。这样您就可以准确地看到保存失败的情况以及图表的状态。

编辑01:

好的,我查看了您的代码并发现了问题。

问题是您将 A 的“b”关系设置为 required。当您删除 B 时,它会引发此错误:

2010-02-24 16:14:02.064 CoreDataTestDeleteRule[20887:207] Unresolved error Error Domain=NSCocoaErrorDomain Code=1580 UserInfo=0x3d0b450 "Operation could not be completed. (Cocoa error 1580.)"
2010-02-24 16:14:06.340 CoreDataTestDeleteRule[20887:207] Unresolved error Error Domain=NSCocoaErrorDomain Code=1580 UserInfo=0x3d19980 "Operation could not be completed. (Cocoa error 1580.)", 
    NSLocalizedDescription = "Operation could not be completed. (Cocoa error 1580.)";
    NSValidationErrorKey = b;
    NSValidationErrorObject = <A: 0x3b2faf0> (entity: A; id: 0x3d05330 <x-coredata://6870AF7C-E28F-4B4E-80AB-09C648651179/A/p1> ; data: 
    b =     (
    );
    name = a;

(顺便说一句,数字核心数据错误代码的文本错误可以在CoreDataErrors.h中找到。)

这是有道理的,因为您要求 A 有一个 b,然后您删除所有 b。只需将 A->>B 关系设置为 optional 即可防止错误并允许代码正常运行。

您的代码还有一些其他问题。一些自动生成的类没有正确显示。例如,B.h 的界面如下所示:

#import <CoreData/CoreData.h>

@class A;

@interface B :  NSManagedObject  



@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) A * a;
@property (nonatomic, retain) NSManagedObject * c;

@end

什么时候应该是这样的:

#import <CoreData/CoreData.h>

@class A;
@class C;

@interface B :  NSManagedObject  



@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) A * a;
@property (nonatomic, retain) C * c;

@end

我不确定为什么它们没有正确生成。

我还建议不要使用短变量和类名。 Objective-c 有一个全局名称空间,使用单字母符号会导致名称冲突。你永远不知道还有谁着急。我推荐使用旧的二战风格的拼音字母(现代的也有冲突的风险)和名称测试类:Adam、Baker、Charlie、David、Eddy 等。

看起来我们都专注于 BC>D 关系,而忽略了放眼更远的地方。是军方“目标锁定”的程序员调试版。你被困在一个问题的概念上,无法摆脱自己。

【讨论】:

你好TechZen,我没有提到除了A的b和B的a之外所有的关系都是可选的。感谢您的建议,我会尝试调试并报告结果。 我把C-->D的Cascade改成Nullify,删除没问题,但是好像D的所有对象都没有删除。因此,当我导航回屏幕以重新填充 B&C 时,我尝试再次添加 D,它被中断了。 @TechZen,我觉得问题恰恰出在C和D的关系上,当我添加一个新的对象D时,立即删除失败,但是当没有D时,没有问题。当 C&D 之间的关系是可选的时,C&D 有什么问题? 我不知道,让我考虑一下。可以尝试的事情: () 尝试从图中删除 E,即打破关系 DE,看看是否有帮助。 () 不要从 B 开始删除,而是从 C 开始。 () 在删除之后但在保存之前,在每个 C 中的所有 D 上调用 isDeleted。看看它们是否实际上都标记为删除以及他们仍然指向哪个 C。 ()如果整个图表中只有一个 D 出现问题,请在调用 delete 之前和之后(但在保存之前)转储它,以查看是否有任何关键变化。 这些实体/托管对象中是否有任何未在模型中表示的实例属性?如果是这样,请仔细检查它们。【参考方案2】:

您在 NSFetchedResultsControllerDelegate 方法中做了什么?根据堆栈跟踪,您似乎在其中一个中做了一些有趣的事情。理想情况下,这些代表应该只更新他们所附加的UITableView。如果您在其中一种方法中使用NSManagedObject 实例或NSManagedObjectContext 执行某些操作,则可能会导致这样的崩溃。

我建议在objc_exception_throw 上设置一个断点,这样可以为您提供有关问题发生的确切点的更多信息。

更新

我查看了代码,您正试图删除 B,而 A 具有该 B 的必需属性。这会导致验证错误。您不能删除另一个对象作为必需关系具有的对象。

【讨论】:

嗨,Marcus,我试图在一个新的简单项目中重新创建这种情况,该项目在图像中具有完全相同的实体。里面有三个帮助函数来生成错误,我也包含了一个 README 文件。堆栈跟踪来自其他应用程序。如果您无法测试我的应用程序,我将尝试再次更新堆栈跟踪。 @Marcus,非常感谢,我已经解决了这个问题,它在于 NSFetchedResultsController Delegate 方法。你说的对。我仔细检查了视图控制器,发现我不小心把它们都留空了,没有任何实现。我已经通过删除所有问题解决了这个错误!谢谢分享:-)

以上是关于核心数据:-deleteObject:崩溃,删除规则是原因吗?的主要内容,如果未能解决你的问题,请参考以下文章

崩溃:commitEditingStyle -deleteObject 为零

UITableView中的deleteObject错误,无法复制

核心数据删除对象:不工作?

快速删除过去保存的核心数据条目

使用 Swift 3 删除核心数据托管对象

带有 EXC_BAD_ACCESS 的 Core Data deleteObject 应用程序崩溃