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

时间:2010-02-24 11:50:35

标签: iphone core-data schema exc-bad-access

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

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:&amp; 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&amp;时,这是控制台中的日志。 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文本。希望我已经提供了足够的信息。

2 个答案:

答案 0 :(得分:3)

我认为这个问题可能存在于C和D之间的必要关系中。如果你配置的图形如下:

  1. 每个C至少需要一个D.
  2. C的许多实例指向相同的D.
  3. 然后在某个时刻,C可能会发现它的必需关系已经无效。如果它仍然试图访问D,那将触发EXC_BAD_ACCESS。 (如果每个E需要一个D,你可能会遇到同样的问题)

    要调试我建议,

    • 将关系C - > D设置为可选,并查看错误是否消失。
    • 从C - > D开始,将级联更改为空,并查看错误是否消失。
    • 如果您有类,请检查实例是否在实体图外部不共享某些对象。例如,C和D类都引用了相同的图像,但该图像不是实体的一部分。如果未正确保留外部引用,也可能导致类似的崩溃。
    • 在删除每个B的呼叫后立即将保存移动到B.在删除之前记录每个B和它的Cs。通过这种方式,您可以确切地看到保存失败以及图表处于什么状态。

    Edit01:

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

    问题是您将A设置的“b”关系设置为必需。删除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;
    

    BTW,可以在CoreDataErrors.h中找到数字核心数据错误代码的文本错误。

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

    您的代码也存在其他一些问题。一些自动生成的类没有正确结果。例如,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具有全局名称空间,使用单个字母符号是名称冲突的邀请。你永远不知道还有谁匆忙。我建议使用旧的二战风格的拼音字母(现代风格碰撞)和名称测试类:亚当,贝克,查理,大卫,艾迪等。

    看起来我们都专注于B&lt; - &gt;&gt;&gt; D关系而忽略了更远的地方。这是程序员对军方“目标固定”的调试版本。你会陷入一个问题的概念,不能动摇自己。

答案 1 :(得分:2)

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

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

更新

我查看了代码并且您尝试删除B而A具有该B的必需属性。这导致验证错误。您无法删除另一个对象具有所需关系的对象。