I have a set up a timer to report periodically on some event to an outside server with which I communicate asynchronously, the timer fires on the main thread to execute this code:
- (void) sendPendingEvents
{
NSManagedObjectContext *moc = [self newPrivateContext];
[moc performBlock:^{
NSArray *eventsToSend = [TrackingEvent findByAttribute:@"sentToServer" withValue:[NSNumber numberWithBool:NO] andOrderBy:@"timestamp" ascending:YES inContext:moc];
for (TrackingEvent *event in eventsToSend) {
[self RESTsendTrackingEvent:event];
}
}];
}
Where newPrivateContext creates a new private queue context with the main context as a parent. The idea is that all this should be done asynchronously in the background.
However this fails because RESTsendTrackingEvent: is itself asynchronous (it uses a NSURLSession) and it updates the TrackingEvent (to set its "sentToServer" flag to true) on its completion block.
The problem is that the completion block is called later, when sendPendingEvents has finished running, at which point the managedObjectContext doesn't even exist any more. And indeed I have this Core Data error:
CoreData: error: Mutating a managed object 0x7b7309e0 <x-coredata:///TrackingEvent/t8B8DC387-2B65-4377-A4F4-B82792C89280119> (0x7cbdcce0) after it has been removed from its context.
Which makes complete sense.
I can imagine a couple of ways to fix that (including the cop out to use the main context), but I guess this should be a common occurence.
What would be a nice/elegant pattern to use in cases such as mine?
Thanks
JD