Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Random EXC_BAD_ACCESS with persistentStoreCoordinator

From time to time my app crashes before it is fully loaded right at the following line:

if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])

The complete method where this if state is located looks as follows (I think this is pretty standard):

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

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

    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return __persistentStoreCoordinator;
}

Update

The crash happens on the second time the -(NSPersistentStoreCoordinator *)persistentStoreCoordinator method is called. EDIT The frist time it is called from the first viewController that is visible:

- (void)updateStats {
    NSLog(@"Updating stats");
    dispatch_queue_t request_queue = dispatch_queue_create("updateNumberOfSchedules", NULL);
    dispatch_async(request_queue, ^{
         AppDelegate *theDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
    [context setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]];
    ...
    });
}

The second time (when the crash sometimes occurs when my DeviceLinker class is going to check the database for inactive links in my checkInactiveLinks method. This method is called upon launch in applicationDidBecomeActive:

-(void) checkInactiveLinks {
    AppDelegate *theDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *newMoc = [[NSManagedObjectContext alloc] init];
    [newMoc setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]];
    ...
}

Correct me if I'm wrong but reading my code I would think that on the second time the persistentStoreCoordinator getter is called it should return __persistentStoreCoordinator and not allocate and init a new one...

UPDATE 2 On the same exact line at the if statement I get this from time to time too:

-[__NSCFDictionary _hasPrecomputedKeyOrder]: unrecognized selector sent to instance 0x7dd3770

UPDATE 3

I edited my build scheme and turned on zombies and log exceptions under the diagnostics tab. Now I see -[NSPersistentStoreCoordinator unlock]: message sent to deallocated instance 0x8916090. Note that I don't have any explicit locks in my code.

like image 899
Pieter Avatar asked Apr 30 '12 18:04

Pieter


2 Answers

It looks like you are getting into that piece of code from multiple threads at the same time. When you do lazy instantiation, you must make sure the "first time" through only one thread of execution will pass at the same time. You can use the following strategy to synchronize access to it on the main thread.

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

    // Add this block of code.  Basically, it forces all threads that reach this
    // code to be processed in an ordered manner on the main thread.  The first
    // one will initialize the data, and the rest will just return with that
    // data.  However, it ensures the creation is not attempted multiple times.
    if (![NSThread currentThread].isMainThread) {
        dispatch_sync(dispatch_get_main_queue(), ^{
            (void)[self persistentStoreCoordinator];
        });
        return __persistentStoreCoordinator;
    }

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

    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return __persistentStoreCoordinator;
}
like image 124
Jody Hagins Avatar answered Nov 13 '22 10:11

Jody Hagins


I am using GCD to use threading.

And:

From time to time my app crashes before it is fully loaded right at the following line:

Sounds like the classic symptoms of a concurrency related bug; intermittent and seemingly in the wrong spot.

CoreData has very specific concurrency requirements. Are you meeting them?

like image 39
bbum Avatar answered Nov 13 '22 10:11

bbum