iosnszombienszombieenabled

iOS app crashes with objc_release EXC_BAD_ACCESS on startup


My app keeps (which uses ARC) crashes right after startup, with the following backtraces of the threads:

enter image description here

enter image description here

The weird thing is that when I try to run the app with Instruments-Zombie tool, the app works fine and doesn't crash, but I get no zombie accessed notification on the instrument panel. If it works fine with zombies flag enabled, I would at least expect to see one zombie notification!

Any ideas on how to further approach this issue?

Edit

So here is some code, and I've managed to narrow the problem to a specific code path.

XYZStore.h/m:

@property (nonatomic,strong,readonly) NSManagedObjectContext* mainManagedObjectContext;

@implementation XYZStore

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite"];

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    return _persistentStoreCoordinator;
}

- (NSManagedObjectContext *)mainManagedObjectContext
{
    if (_mainManagedObjectContext != nil) {
        return _mainManagedObjectContext;
    }

    _mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    _mainManagedObjectContext.persistentStoreCoordinator = [self persistentStoreCoordinator];
    return _mainManagedObjectContext;
}

Initial view controller:


-(void)awakeFromNib
{
    XYZAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *moc= delegate.store.mainManagedObjectContext; // managed context object from XYZStore

    NSEntityDescription *entityDescription = [NSEntityDescription
                                              entityForName:@"Person" inManagedObjectContext:moc];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];

    [request setEntity:entityDescription];

    NSError *error;
    NSArray *results = [moc executeFetchRequest:request error:&error];
    for (id *obj in results) {
        NSLog(@"%p", obj);
    }
    NSLog(@"%d", [results count]); // print "232"
}

This code path throws the exception I attached above (objc_release).

Two important things I've noticed:

1) If I insert [moc reset] after the fetch, the exception is not raised anymore (this is of course not scalable for my program, as I am dealing with NSFetchRequestControllers and such).

2) If I don't use the main object context, but a an object context in a private queue, then the exception is not raised as well.

Full backtrace:

(lldb) thread backtrace

  • thread #1: tid = 0x9c9a, 0x03b39e85 libobjc.A.dylibobjc_release + 21, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xd0000010) * frame #0: 0x03b39e85 libobjc.A.dylibobjc_release + 21 frame #1: 0x03b3ad32 libobjc.A.dylib(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 586 frame #2: 0x04153678 CoreFoundation_CFAutoreleasePoolPop + 24 frame #3: 0x01123184 Foundation-[NSAutoreleasePool drain] + 149 frame #4: 0x0379a9ec CoreData_performRunLoopAction + 348 frame #5: 0x041949de CoreFoundation`CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION
  • 30 frame #6: 0x04194920 CoreFoundation__CFRunLoopDoObservers + 400 frame #7: 0x0418a35a CoreFoundation__CFRunLoopRun + 1226 frame #8: 0x04189bcb CoreFoundationCFRunLoopRunSpecific + 443 frame #9: 0x041899fb CoreFoundationCFRunLoopRunInMode + 123 frame #10: 0x05c4d24f GraphicsServicesGSEventRunModal + 192 frame #11: 0x05c4d08c GraphicsServicesGSEventRun + 104 frame #12: 0x01de48b6 UIKitUIApplicationMain + 1526 frame #13: 0x000611cd Contacitmain(argc=1, argv=0xbfff83b0) + 141 at main.m:16 frame #14: 0x0482cac9 libdyld.dylib`start + 1

So any help in the investigation would be very much appreciated!


Solution

  • Apparently this was the cause to the problem... In my extended NSManagedObject class I had overriden this method

    - (void)willTurnIntoFault
    {
        [super willTurnIntoFault];
    
        if ([self observationInfo])
        {
            NSLog(@"%@ has observers:\n%@", [self objectID], [self observationInfo]);
        }
    }
    

    Removing this fixed the issue.