My app keeps (which uses ARC) crashes right after startup, with the following backtraces of the threads:
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?
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.
(lldb) thread backtrace
- thread #1: tid = 0x9c9a, 0x03b39e85 libobjc.A.dylib
objc_release + 21, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xd0000010) * frame #0: 0x03b39e85 libobjc.A.dylib
objc_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 CoreFoundation
CFRunLoopRunInMode + 123 frame #10: 0x05c4d24f GraphicsServicesGSEventRunModal + 192 frame #11: 0x05c4d08c GraphicsServices
GSEventRun + 104 frame #12: 0x01de48b6 UIKitUIApplicationMain + 1526 frame #13: 0x000611cd Contacit
main(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!
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.