This is quite funny.
In my application I create thousands of entry in the database (in another thread, I'm using MagicalRecord). Everything seems working fine (from a background/foreground/context point of view).
When, in the main thread, I try to fetch the "just inserted" data, I discovered the following behaviour:
- (NSArray *) familiesInCompany:(Company *) company {
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"company == %@", company];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"company.name == %@", company.name];
NSArray *first = [Family MR_findAllSortedBy:@"name" ascending:YES withPredicate:predicate1];
NSArray *second = [Family MR_findAllSortedBy:@"name" ascending:YES withPredicate:predicate2];
NSArray *third = [Family MR_findByAttribute:@"company" withValue:company andOrderBy:@"name" ascending:YES];
return second;
}
Now what I get is:
- first: is an empty array
- second: contains all the
Family
objects, as expected
- third: is an empty array.
By debugging the SQL statement I get the following:
The "first" statement:
CoreData: annotation: total fetch execution time: 0.0000s for 0 rows.
The "second" statement":
CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.ZCOMPANY FROM ZFAMILY t0 JOIN ZCOMPANY t1 ON t0.ZCOMPANY = t1.Z_PK WHERE t1.ZNAME = ? ORDER BY t0.ZNAME
CoreData: annotation: sql connection fetch time: 0.0005s
CoreData: annotation: total fetch execution time: 0.0007s for 2 rows.
The "third" statement:
CoreData: annotation: total fetch execution time: 0.0000s for 0 rows.
The hilarious thing is that I close the application (I mean really manually terminate it) and and I open it back, all the three "fetching" statements work.
Why the first and the third fetch statements seem to never being executed? How to dig into the problem?
I had this same issue, this is what I figured out, and how I resolved it.
Magical Record has a root NSManagedObjectContext
as a parent of the default NSManagedObjectContext
. When I create an NSFetchedResultsController
in the default context, everything seems to work fine, just like you.
The problem is that all the new NSManagedObject
's come back with their still-temporary ObjectID
's. So, in my case, I was using an NSPredicate
to scope a query on an associated table. I didn't just call the association method because I didn't want to load everything into memory and wanted NSFetchedResultsController
to handle changes, for me.
With the temporary ObjectID
the query finds zero results and that's exactly what it displays.
Apparently the child context (default) doesn't get the benefit of the transformation to non-temporary ID's, even though it's been persisted to the backing store.
Even worse badness happened when I tried to force the issue with obtainPermanentIDsForObjects:error:
. Core Data complained that it could not satisfy a fault for my instance. Nevermind, there's no way it was actually a fault. Simply refreshing the object had no effect, either. I suspect this is a Core Data bug that hardly no one tickles because they just use the association methods to get an NSSet.
My fix was to use the parent context for the NSFetchedResultsController
, just like in this question, Magical Record, saving, and NSFetchedResultsController.
I was already wrapping the default in a new child context upon edit and, therefore, copying the instances into that editing context with createInContext
, so I didn't have to do any extra work beyond just adding .parentContext
to the argument.
Incidentally, this only ever happened on new instances of the source of the association. Once an instance was there from startup, it had a non-temporary ObjectID
and never had the issue.