I'm exeperiencing some issues with some Core Data background processing. When I save in my background context it does not seem to push the save up to the main context. When debugging the code I noticed from the background thread that is doing the save operation that it seems to be halted(?) This behaviour causes me to fetch outdated objects.
Stacktrace from save:
Thread 29, Queue : NSManagedObjectContext Queue
#0 0x9a5cf80e in semaphore_wait_trap ()
#1 0x02216f08 in _dispatch_thread_semaphore_wait ()
#2 0x02214b3a in _dispatch_barrier_sync_f_slow ()
#3 0x02214a5c in dispatch_barrier_sync_f ()
#4 0x01dfe03b in _perform ()
#5 0x01dfde9e in -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] ()
#6 0x01ddb33c in -[NSManagedObjectContext save:] ()
#7 0x00096213 in __45-[CoreDataHelper saveInManagedObjectContext:]_block_invoke_0 at /Users/peterwarbo/Documents/Projects/MessagePlanr/MessagePlanr/CoreDataHelper.m:307
#8 0x01e734b3 in developerSubmittedBlockToNSManagedObjectContextPerform_privateasync ()
Save method:
- (void)saveInManagedObjectContext:(NSManagedObjectContext *)context {
if (context == nil) {
// Use default MOC
context = self.managedObjectContext;
NSError *error = nil;
if (context != nil)
{
if ([context hasChanges] && ![context save:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
*/
DLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
} else {
// First save (child) context
[context performBlock:^{
NSError *error = nil;
if ([context hasChanges] && ![context save:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
*/
DLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}];
// Then save parent context
[self.managedObjectContext performBlock:^{
NSError *error = nil;
if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
*/
DLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}];
}
}
This is the method that saves, Reminder is a NSManagedObject, when operation is complete I call a completion block. However in the completion block when fetching some NSManagedObjects they have not been updated (due to the save halting I presume?)
- (void)checkOverdueRemindersInBackgroundWithCompletionBlock:(void (^)(NSInteger overdueCount, NSArray *reminders))block {
DLogName()
// Creating a new MOC for thread safety
NSManagedObjectContext *syncContext = [self threadedManagedObjectContext];
[syncContext performBlock:^{
NSArray *reminders = [self fetchEntity:APReminderEntity predicate:nil andSortDescriptors:nil inManagedObjectContext:syncContext];
NSInteger overdueCount = 0;
for (Reminder *reminder in reminders) {
[reminder checkOverdue]; // Checks if object is overdue and sets a flag if it is
[self saveInManagedObjectContext:syncContext];
if (reminder.status.intValue == RMReminderStatusOverdue) {
overdueCount++;
}
}
block(overdueCount, reminders);
}];
}
threadedManagedObjectContext method:
- (NSManagedObjectContext *)threadedManagedObjectContext {
NSManagedObjectContext *threadedMoc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
threadedMoc.parentContext = self.managedObjectContext; //self.managedObjectContext is of type NSMainQueueConcurrencyType
return threadedMoc;
}
saveInManagedObjectContextmethod, try to save your parent context inside the child contextperformBlockmethod and inside theifstatement - YamanperformBlock*API. - Peter Warbo