I'm doing 2 Core Data fetches that when they are performed at around the same time they will cause a deadlock in the main thread causing my app to freeze.
The fetches are made on the main thread. One way to deal with it would be to ensure that the fetches are not made around the same time but I have no control of when the fetches will be made. Is there any other way to avoid this deadlock?
Stack-trace when pausing the app is:
#0 0x9a5d191a in __psynch_mutexwait ()
#1 0x9166713b in pthread_mutex_lock ()
#2 0x01e5d591 in -[_PFLock lock] ()
#3 0x01e5d56a in -[NSPersistentStoreCoordinator lock] ()
#4 0x01e720ee in -[NSPersistentStoreCoordinator executeRequest:withContext:error:] ()
#5 0x01e70539 in -[NSManagedObjectContext executeFetchRequest:error:] ()
#6 0x0007cd62 in -[CoreDataHelper fetchEntity:predicate:andSortDescriptors:inManagedObjectContext:] at /xxx/CoreDataHelper.m:150
#7 0x000075f6 in -[RemindersListViewController refreshReminders] at /xxx/RemindersListViewController.m:64
#8 0x000082f8 in -[RemindersListViewController refreshGUI] at /xxx/RemindersListViewController.m:187
#9 0x00003735 in __58-[AppDelegate setTabCountAndScheduleRemindersInBackground]_block_invoke_2 at /xxx/AppDelegate.m:114
#10 0x022dc53f in _dispatch_call_block_and_release ()
#11 0x022ee014 in _dispatch_client_callout ()
#12 0x022de7d5 in _dispatch_main_queue_callback_4CF ()
#13 0x0261aaf5 in __CFRunLoopRun ()
#14 0x02619f44 in CFRunLoopRunSpecific ()
#15 0x02619e1b in CFRunLoopRunInMode ()
#16 0x02fd77e3 in GSEventRunModal ()
#17 0x02fd7668 in GSEventRun ()
#18 0x00d9dffc in UIApplicationMain ()
#19 0x0000297d in main at /xxx/main.m:16
EDIT: The different parts accessing Core Data are trying to do a fetch request. They are both calling this method:
NSArray *reminders = [[CoreDataHelper sharedInstance] fetchEntity:APReminderEntity predicate:nil andSortDescriptors:[NSArray arrayWithObject:dateAscendingDescriptor] inManagedObjectContext:nil];
CoreDataHelper.m
- (NSArray *)fetchEntity:(NSString *)entity predicate:(NSPredicate *)predicate andSortDescriptors:(NSArray *)sortDescriptors inManagedObjectContext:(NSManagedObjectContext *)context {
DLogName()
if (context == nil) {
// Use default MOC
context = self.managedObjectContext;
}
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entity inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
if (predicate != nil) {
[request setPredicate:predicate];
}
if (sortDescriptors != nil) {
[request setSortDescriptors:sortDescriptors];
}
NSError *error = nil;
NSArray *entities = [context executeFetchRequest:request error:&error];
if (entities == nil) {
DLog(@"There was an error fetching entity: %@ Error: %@", entity, [error userInfo]);
entities = [NSArray array];
}
return entities;
}
EDIT 2: I just tried putting my fetch request inside a @synchronized
block (as suggested in this post) and so far it seems to work out great... I am accessing my MOC on the correct thread.. the MOC is initialized as _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];