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.
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;
}
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With