开发者

exc_bad_access on insertNewObjectForEntityForName:inManagedObjectContext

I wrote a minimal code example of the issue I am having. I implemented the background work two ways: manually spawning threads and letting NSOperation handle threading. In both cases I am creating NSManagedObjectContexts for each thread/operation.

When I spawn the threads myself with performSelectorInBackground:withObject: everything works fine. When I switch to passing my objects off to an NSOperationQueue I see the following errors when attempting to save the operations NSManagedObjectContext.

-EXC_BAD_ACCESS - Serious application error. Exception was caught during Core Data change processing: *** -[NSCFSet addObject:]: attempt to insert nil with userInfo (null) - _referenceData64 only defined for abstract class. Define -[NSTemporaryObjectID_default _referenceData64]!

I believe the bug, especially given the last error, has to do with using a temporary objectID to pass objects between threads/contexts. Possibly, even worse, I'm somehow passing NSManagedObjects between threads.

Either way, I can't find any code which would suggest I am doing so.

My minimal code example can be found here.

Most of the work is done in the AppDelegate in awakeFromNib. Set EXECUTE_WITH_NSOPERATION to 0 to run with performSelectorInBackground:withObject:. Leave EXECUTE_WITH_NSOPERATION on 1 to execute with the NSOperationQueue which creates a bunch of MCBoardParse objects.

I'm only seeing this under 10.6.

Original

I have a Cocoa application built on 10.5 frameworks. In an NSOperation In a loop I am quickly creating hundreds of NSManagedObjects. Frequently the creation of those NSManagedObejcts will crash with a EXC_BAD_ACCESS error. This happens under both reference counted memory management and garbage collection.

    for (offsetCount; offsetCount < [parsedData count]; offsetCount++) {
  NSManagedObject *child = [NSEntityDescription insertNewObjectForEntityForName:@"Thread" inManag开发者_Python百科edObjectContext:[self moc]];
  Thumbnail *thumb = [Thumbnail insertInManagedObjectContext:[self moc]];
  Image *image = [Image insertInManagedObjectContext:[self moc]];
  ...
 }

Thumbnail and Image are both subclasses of NSManagedObject generated with mogenerator. insertInManagedObjectContext: looks like

    NSParameterAssert(moc_);
    return [NSEntityDescription insertNewObjectForEntityForName:@"Thumbnail" inManagedObjectContext:moc_];

    NSParameterAssert(moc_);
 return [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:moc_];
The NSManagedObjectContext returned by [self moc] is created for the NSOperation with 

    NSPersistentStoreCoordinator *coord = [(MyApp_AppDelegate *)[[NSApplication sharedApplication] delegate] persistentStoreCoordinator];
 self.moc = [[NSManagedObjectContext alloc] init];
 [self.moc setPersistentStoreCoordinator:coord];
 [[NSNotificationCenter defaultCenter] addObserver:self
      selector:@selector(contextDidSave:) 
       name:NSManagedObjectContextDidSaveNotification 
     object:self.moc];
 [self.moc setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
 [self.moc setUndoManager:nil];
 [self.moc setRetainsRegisteredObjects:YES];

moc is defined as (nonatomic, retain) and synthesized. As far as I can tell it, the persistent store and my appDelegate have no reason to be and are not being garbage collected.

The stack trace looks like

Thread 2 Crashed:  Dispatch queue: com.apple.root.default-priority
0   libauto.dylib                  0x00007fff82d63600 auto_zone_root_write_barrier + 688
1   libobjc.A.dylib                0x00007fff826f963b objc_assign_strongCast_gc + 59
2   com.apple.CoreFoundation       0x00007fff88677068 __CFBasicHashAddValue + 504
3   com.apple.CoreFoundation       0x00007fff88676d2f CFBasicHashAddValue + 191
4   com.apple.CoreData             0x00007fff82bdee5e -[NSManagedObjectContext(_NSInternalAdditions) _insertObjectWithGlobalID:globalID:] + 190
5   com.apple.CoreData             0x00007fff82bded24 -[NSManagedObjectContext insertObject:] + 148
6   com.apple.CoreData             0x00007fff82bbd75c -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:] + 716
7   com.apple.CoreData             0x00007fff82bdf075 +[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:] + 101
8   com.yourcompany.MyApp         0x000000010002c7a7 +[_Thumbnail insertInManagedObjectContext:] + 256 (_Thumbnail.m:14)
9   com.yourcompany.MyApp         0x000000010002672d -[ThreadParse main] + 10345 (ThreadParse.m:174)
10  com.apple.Foundation           0x00007fff85ee807e -[__NSOperationInternal start] + 698
11  com.apple.Foundation           0x00007fff85ee7d23 ____startOperations_block_invoke_2 + 99
12  libSystem.B.dylib              0x00007fff812bece8 _dispatch_call_block_and_release + 15
13  libSystem.B.dylib              0x00007fff8129d279 _dispatch_worker_thread2 + 231
14  libSystem.B.dylib              0x00007fff8129cbb8 _pthread_wqthread + 353
15  libSystem.B.dylib              0x00007fff8129ca55 start_wqthread + 13

My app is crashing in other places with EXC_BAD_ACCESS but this is code that it happens most with. All of the stack traces look similar and have something to do with CFHash.


If you are crashing with a exc_bad_access that means you are over-releasing an object or you are calling methods on an object after it has been released. Both of these situations are bad and have nothing to do with Core Data. The fact that you are using garbage collection is probably a clue that something is getting dereferenced and therefore getting garbage collected before you expect it to.

First question though, are you creating a new NSManagedObjectContext for each one of these NSOperation instances?

Second, I would recommend turning on NSZombie (which I believe you can do through instruments now) and that will help narrow down what code is calling an object after release, etc. Doing a Google search on NSZombie and Instruments will turn up several how-to articles.

update

Since this is a 10.6 issue only then it may have to do with the NSOperation instances instead of the Core Data instances. Are your operations flagged as concurrent? The reason I ask is that NSOperation ignores the concurrent flag on 10.6 and that can lead to some nasty surprises.

update 2

Just a note while I am reviewing the overall problem. The line:

self.moc = [[NSManagedObjectContext alloc] init];

Will leak memory (at least while GC is off) if you do not have a release as the alloc init will increment the retain count and then the [self setMoc:] call also increments the retain count.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜