Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSFetchedResultsController missing some objects

I'm facing a strange issue where an NSFRC fetchedObjects array returning not all the objects it should. To give you some context, my application has several list view controllers, each of them having an NSFRC. I'm updating the list view within the delegate method controllerDidChangeContent. The problem I'm facing is the following: after storing an object in a background MOC and saving it, the controllerDidChangeContent is invoked but the object I just saved in the background thread doesn't show up in the NSFRC. Here is a piece of code that I'm using to check this:

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    NSManagedObjectContext *context = controller.managedObjectContext;
    NSError *error = nil;
    NSArray *array = [context executeFetchRequest:controller.fetchRequest error:&error];
    if (nil != array) {
        NSUInteger count = MIN(controller.fetchedObjects.count, array.count);
        for (NSUInteger index=0; index<count; index++) {
            NSManagedObject *a = array[index];
            NSManagedObject *b = controller.fetchedObjects[index];
            // Here you will see that sometimes the objects don't match
            NSLog(@"%d: %@ <--> %@", index, [[a body] text], [[b body] text]);
        }
    }
}

I'm expecting the NSFRC fetchedObjects array to be identical to the array returned by a manual executeFetchRequest (I'm using the NSFRC fetchRequest to manually fetch the data). However, this is not the case. The manual executeFetchRequest returns more object than the NSFRC fetchedObjects. Does anyone know what's going on? I've turned the caching on the NSFRC off but the same behavior is reported.

Thanks!

=== Update ====

Some update on that issue. I think there is a bug in Core Data because I was able to see some inconsistent results from the NSFRC and moreover was able to fix the problem by a workaround involving "touching" the object in question. Here is a scenario that explains what is happening:

Imagine the following Core Data model where: - There are Cat objects and Master objects. - A Cat can have one or more Master. - A Master can have one or more Cat. - A first NSFRC (let's call it NSFRC_A) is created to fetch all the cats with master named "Master_A". The predicate is { ANY master.name == "Master_A" }. - A second NSFRC (let's call it NSFRC_B) is created to fetch all the cats with master named "Master_B". The predicate is { ANY master.name == "Master_B" }. - There is a main managed object context that is used in the UI thread only - There is a background managed object context created for each background thread, using the same persistent store as the main managed object context.

A cat named "Cat_A" is created in the background and assigned to master "Master_A". After the background context is saved, the main context is updated appropriately. At this point, the NSFRC_A notifies its delegate that a change has occurred and correctly reports "Cat_A".

Later on, in a background thread, the same cat "Cat_A" is assigned master "Master_B". After the background context is saved, the main context is updated appropriately. At this point, the NSFRC_A notifies its delegate of that change and correctly reports "Cat_A". NSFRC_B also notifies its delegate of that change but doesn't report "Cat_A" (it is missing from its fetchedObjects). However, if I manually perform a fetch using the same fetchRequest as NSFRC_B, I can see "Cat_A" being returned. The weird thing is that the "Cat_A" instance being returned is marked as a fault which explains why NSFRC_B doesn't return the "Cat_A" because it doesn't see it in memory.

This is a bug because I can fix that behavior by simply logging the "Cat_A" relationship to master when the changes from the background thread are merged into the main context: the logging basically touches the object and forces it to be realized into memory.

like image 583
jbovet Avatar asked Dec 11 '12 22:12

jbovet


1 Answers

The problem appears to be a limitation of the NSFRC. According to this thread on the Apple Forum (https://devforums.apple.com/message/765374): "The limitation being that a fetched results controller for entity A won't always catch an update to entity B that would cause the predicate to change.". To solve the issue, I had to dirty the object I'm looking for before it is being merged into the main thread: then the NSFRC detects that change.

like image 89
jbovet Avatar answered Nov 10 '22 16:11

jbovet