Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSFetchedResultsController with predicate ignores changes merged from different NSManagedObjectContext

I am presenting table view contents using NSFetchedResultsController which has a predicate:

[NSPredicate predicateWithFormat:@"visible == %@", [NSNumber numberWithBool:YES]]

On background thread using separate NSManagedObjectContext I update few of the entities and change theirs visible value from NO to YES. Save, merge changes in main thread's NSManagedObjectContext. But NSFetchedResultsController's fetchedObjects doesn't change. Also controller doesn't call -controller:didChangeObject:... on delegate. If entities are updated on main thread in identical manner (my test app calls the same method), everything works as expected.

Also Notification's NSUpdatedObjectsKey contains those objects.

Currently the only solutions I've found is to call for each of NSUpdatedObjectsKey entities:

NSManagedObjectContext *context = ... // main thread context
[context existingObjectWithID:[object objectID] error:nil]

This issue is only with updated objects which previously didn't match the predicate.

Am I missing something obvious?

like image 962
ampatspell Avatar asked Oct 13 '10 12:10

ampatspell


2 Answers

Turns out main NSManagedObjectContext didn' t event fire NSManagedObjectContextObjectsDidChangeNotification for updated objects because it is not done for faulted objects.

Generic fix (or keep a track of object IDs that needs this treatment):

NSManagedObjectContext *context = [self managedObjectContext];
for(NSManagedObject *object in [[notification userInfo] objectForKey:NSUpdatedObjectsKey]) {
  [[context objectWithID:[object objectID]] willAccessValueForKey:nil];
}

[context mergeChangesFromContextDidSaveNotification:notification];

From NSManagedObject Class Reference:

You can invoke this method with the key value of nil to ensure that a fault has been fired, as illustrated by the following example.

like image 57
ampatspell Avatar answered Oct 04 '22 05:10

ampatspell


You have to call processPendingChanges on your Background-NSManagedObjectContext after you merged the changes from an other NSManagedObjectContext.

See CoreData Programming Guide:

Note that the change notification is sent in NSManagedObjectContext’s processPendingChanges method. The main thread is tied into the event cycle for the application so that processPendingChanges is invoked automatically after every user event on contexts owned by the main thread. This is not the case for background threads—when the method is invoked depends on both the platform and the release version, so you should not rely on particular timing. If the secondary context is not on the main thread, you should call processPendingChanges yourself at appropriate junctures.

like image 26
Artur Friesen Avatar answered Oct 04 '22 04:10

Artur Friesen