核心数据:解决奇怪的EXC_BAD_ACCESS错误

时间:2011-06-15 08:44:17

标签: objective-c core-data exception-handling exc-bad-access

我面临着一个非常奇怪的核心数据问题。我们来形容它:

解释

假设我有两个模型ModelAModelB。在数据模型中,ModelA引用ModelB作为一对多关联,因此ModelBModelA具有一对一关联。< / p>

更新

当应用程序启动时(特别是在首次启动时)或用户要求时,我必须为每个ModelB实例创建或更新所有ModelA个实例。 ModelA个实例已预先确定。对于每个ModelA实例,我有大约200个ModelB实例。

我使用这样的代码:

ModelB *model = [NSEntityDescription insertNewObjectForEntityForName:@"ModelB"
                                              inManagedObjectContext:context];
model.value = [NSNumber numberWithDouble:myValue];
model.modelA = modelA; // I pass modelA as a parameter to the function
[modelA addModelBObject:model];

我不会立即保留数据(因为我需要保存大量数据),但是我会在流程结束时这样做。

错误

有时候,有时候,我在此行收到EXC_BAD_ACCESS错误:

model.value = [NSNumber numberWithDouble:myValue];

启用僵尸,我只能看到愚蠢的EXC_BAD_ACCESS,不能再看到任何信息了。

真奇怪的错误

我试图以不同的方式设置该值,但没有任何改变。然后,我尝试retain NSNumber,但没有任何改变。然后,最后,我尝试retain模型创建后,我得到了通常的EXC_BAD_ACCESS,但相应地创建了模型,也就是说:

ModelB *model = [[NSEntityDescription insertNewObjectForEntityForName:@"ModelB"
                                               inManagedObjectContext:context] retain];

想法?

您对如何解决此问题有任何想法吗?难道我做错了什么? 顺便说一句,如果我减慢了很多事情(比如每次创建新模型时都保存上下文),这个问题显然就不会发生了,但这确实会让整个应用程序变慢... < / p>

修改

在极少数情况下,我会得到这个堆栈跟踪:

Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null)
2011-06-15 11:36:59.864 myApp[457:607] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'
*** Call stack at first throw:
(
0   CoreFoundation                      0x313dc64f __exceptionPreprocess + 114
1   libobjc.A.dylib                     0x34b3dc5d objc_exception_throw + 24
2   CoreFoundation                      0x313dc491 +[NSException raise:format:arguments:] + 68
3   CoreFoundation                      0x313dc4cb +[NSException raise:format:] + 34
4   CoreFoundation                      0x31351089 -[__NSCFSet addObject:] + 152
5   CoreData                            0x35136dd9 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processPendingUpdates:] + 524
6   CoreData                            0x350f4b3d -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 724
7   CoreData                            0x351363a5 -[NSManagedObjectContext processPendingChanges] + 16
8   CoreData                            0x350d027f _performRunLoopAction + 126
9   CoreFoundation                      0x313b3a35 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 16
10  CoreFoundation                      0x313b5465 __CFRunLoopDoObservers + 412
11  CoreFoundation                      0x313b675b __CFRunLoopRun + 854
12  CoreFoundation                      0x31346ec3 CFRunLoopRunSpecific + 230
13  CoreFoundation                      0x31346dcb CFRunLoopRunInMode + 58
14  GraphicsServices                    0x3658841f GSEventRunModal + 114
15  GraphicsServices                    0x365884cb GSEventRun + 62
16  UIKit                               0x368ded69 -[UIApplication _run] + 404
17  UIKit                               0x368dc807 UIApplicationMain + 670
18  myApp                               0x000028cf main + 82
19  myApp                               0x00002878 start + 40
)
terminate called after throwing an instance of 'NSException'

编辑2

这是异常的堆栈跟踪:

#0  0x313f1460 in __CFBasicHashAddValue ()
#1  0x3133fff8 in CFBasicHashAddValue ()
#2  0x31344162 in CFSetAddValue ()
#3  0x31351012 in -[__NSCFSet addObject:] ()
#4  0x3514211a in _PFFastMOCObjectWillChange ()
#5  0x3512ed46 in _PF_ManagedObject_WillChangeValueForKeyIndex ()
#6  0x35132e7e in _sharedIMPL_setvfk_core ()
#7  0x3513316a in _svfk_2 ()
#8  0x0003b750 in -[_TassoStorico setValoreValue:] (self=0x6d97bf0, _cmd=0x49064, value_=1.02600002) at _TassoStorico.m:87
#9  0x0001b62e in -[EuriborParser(hidden) readStoricoForzato] (self=0x74200d0, _cmd=0x48ff7) at EuriborParser.m:236
#10 0x31349f02 in -[NSObject(NSObject) performSelector:withObject:] ()
#11 0x000441c4 in -[MBProgressHUD launchExecution] (self=0x90a6ff0, _cmd=0x4b83f) at MBProgressHUD.m:482
#12 0x352b3388 in -[NSThread main] ()
#13 0x353255cc in __NSThread__main__ ()
#14 0x34e20310 in _pthread_start ()
#15 0x34e21bbc in thread_start ()

4 个答案:

答案 0 :(得分:9)

CoreData不是线程安全的;看起来这是你的问题,试着看看SO question

答案 1 :(得分:5)

我遇到了类似的问题([managedContext save]上的EA_BAD_ACCESS),这是由一个KeyValueObserver引起的,当它本来应该没有删除时。追踪非常困难。这意味着即使使用ARC,我也会遇到这种行为。

答案 2 :(得分:1)

在持久存储迁移后重置受管对象上下文

我有类似的问题。我还使用了几个线程,并使用了Core Data的migratePersistentStore:toURL:options:withType:error:函数。

在我的情况下,错误发生在另一个线程中的迁移之后。我认为我的问题与线程有关,所以我开始在我的代码中减少线程安全性,但实际上在 之前只需调用managedObjectContext.reset() strong> 对托管对象上下文中的对象执行任何后续操作解决了所有问题。

核心数据行为

奇怪的是,existingObjectWithID:error:总是给我一个不存在的对象的引用,所以我访问不存在的对象并接收EXC_BAD_ACCESS。重置上下文后,该函数暴露了正确的行为。

答案 3 :(得分:0)

这两行是多余的,可能很危险:

model.modelA = modelA; // I pass modelA as a parameter to the function
[modelA addModelBObject:model];

托管对象上下文将自动为您发送互惠关系,因此无需手动执行。事实上,我认为这可能会导致危险的循环。您只能使用一行或另一行,并且将自动设置关系的两侧。我建议只是:

model.modelA = modelA;

...因为它更简单。