Code:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"A"
inManagedObjectContext:moc];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"somePredicate", someObject];
[fetchRequest setPredicate:predicate];
frc = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:moc
sectionNameKeyPath:@"recency"
cacheName:@"frc"];
[fetchRequest release];
frc.delegate = self;
NSError *error;
BOOL success = [frc performFetch:&error];
if (!success) {
NSLog(@"error: %@", error);
}
for (A *a in [frc fetchedObjects]) {
[someMutableArray addObject:a.b];
[someMutableArray addObject:a];
}
Data model:
A and B are entities. A has mandatory to-one relation to B. B has inverse optional to-many relation to A.
Above in English:
Initialize a NSFetchedResultsController to grab some data to power a tableview. After initial fetch, set the data aside for some processing.
Now, later, I try to do this:
id object = [someMutableArray objectAtIndex:someIndex];
NSLog(@"%@", object);
if ([object isMemberOfClass:[B class]]) {
someVar = object.propertyFromB; // problem
} else if ([object isMemberOfClass:[A class]]) {
someVar = object.propertyFromA;
}
Question/problem: the line indicated with "problem" crashes. (EDIT: See below for resolution, but would still like an explanation.)
The NSLog call above yields:
2010-01-30 14:47:14.433 app[22618:20b] <B: 0xf7f750> (entity: B; id: 0xf7ba70 <x-coredata://B01FEC86-14D6-4973-BFDB-EDE4AFD24FDC/B/p4> ; data: <fault>)
2010-01-30 14:47:14.438 app[22618:20b] <A: 0xf7e360> (entity: A; id: 0xf35820 <x-coredata://B01FEC86-14D6-4973-BFDB-EDE4AFD24FDC/A/p6> ; data: {
prop1 = value1;
prop2 = value2;
... etc ...
})
I.e by the problematic line, if the object was of type A, it has been faulted and is available in memory, but if it is B, it's a fault.
My understanding is that the "problem" line should fire the fault and fetch the data from store, but this is not happening. I would like to understand/debug why. I have tried inserting willAccessKey/didAccessKey calls around this. I also tried to set setRelationshipKeyPathsForPrefetching:"b" on the fetch request. Neither worked.
My hypothesis is that since I'm somewhat abusing the NSFetchedRequestController results, the faulting engine gets confused along the way and doesn't fetch the fault when it's supposed to. So I guess a bruteforce way would be to create a new manual fetch request to fetch the related B object at the right time. But is there a better way?
EDIT:
The problem was that object B had a property "description" that I had defined, but that collides with NSObject's built-in name. Xcode always gave me warnings, but I ignored them because I thought "description" internal property/method is only used for dumping strings to console and the like, not internal processing.
The problem disappeared after I made a new version of my model, renaming "description" to something else. All the faulting started to work as expected.
I don't understand, though, what is going on. Is Core Data using the objects' "description" method for some internal introspection?
See Question&Answers more detail:
os