I have an NSFetchedResultsController
and a few operations updates managed objects on separate threads via NSOperationQueue
.
The FRC (with its predicate) looks like this:
- (NSFetchedResultsController*)fetchedResultsController
{
if(fetchedResultsController) return fetchedResultsController;
NSManagedObjectContext* mainContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Check" inManagedObjectContext:mainContext]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"isSync == %@", [NSNumber numberWithBool:NO]]];
[fetchRequest setFetchBatchSize:10];
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil];
fetchedResultsController.delegate = self;
[fetchRequest release], fetchRequest = nil;
return fetchedResultsController;
}
The main thread and the threaded operation have their own managed object contexts. They only share the same coordinator.
Within the threaded operation I change the isSync
property from NO
to YES
. To know what is Check
entity to update, the main context passes to the threaded one a NSManagedObjectID
.
The threaded operation retrieves the managed object like the following:
-(void)main
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSManagedObjectContext *exportContext = [[NSManagedObjectContext alloc] init];
[exportContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
//...
Check* check = (Check*)[exportContext existingObjectWithID:objID error:&error];
check.isSync = [NSNumber numberWithBool:YES];
//...
[exportContext save:&error];
[pool release], pool = nil;
}
When the thread operation calls a save
the mergeChangesFromContextDidSaveNotification
notification is called and the main context merges the changes.
- (void)contextChanged:(NSNotification*)notification
{
if ([notification object] == [self managedObjectContext]) return;
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES];
return;
}
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}
Logging the description of the notification
leads to verify that changes are performed correctly.
My problem
Delegates methods of NSFetchedResultsControllerDelegate
are not called.
This is quite strange since dealing with the same context, the main one, allows to listen for changes and delegates methods are called, e.g. deleting a row object in the UITableView
.
I've found some topics on SO with the same problem. I've tried all the workarounds but I cannot find a valuable solution:
NSFetchedResultsController not showing updates from other contexts
NSFetchedResultsController not firing delegate method after merging update from background thread
Thank you in advance.
Edit
The code above was working in a previous model. Then I created a new model copying (and pasting) entities from the previous one and now it doesn't work anymore.
Suggestions?
Edit 2
This is the predicate I'm using in NSFetchedResultsController
getter. It's my fault, but when I wrote the post I didn't copy it.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"insertionDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
// previous code here
[fetchRequest setSortDescriptors:sortDescriptors];
Now, about Jody last comment
In the main() of your NSOperation, you are loading new objects, and in there it looks like you are setting isSync to YES for each new object. The predicate you use for the fetchedResultsController is looking only for objects that have isSync == NO.
I expecting that when the property isSync
is set to YES, the NSFetchedResultsController
observes that changes and removes rows that not match the predicate. Am I wrong?
Remember that when merging changes from the background to the main thread, I'm able to see that few objects have updated their isSync
property.