问题
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?
回答1:
From Core Data Programming Guide
You are discouraged from overriding description—if this method fires a fault during a debugging operation, the results may be unpredictable—and initWithEntity:insertIntoManagedObjectContext:. You should typically not override the key-value coding methods such as valueForKey: and setValue:forKeyPath:.
-description
is a method in NSObject that returns a string representation of your object. In the line NSLog(@"%@", object)
, -description
is used to get the string that you see in the console. Key-value coding will end up using the method to get the property for the description attribute. This causes a whole lot of confusion to Core Data.
The programming guide is being generous when it says "discouraged". They really mean "Yeah, it's going to break your stuff."
That link also has a good list of other methods that will break your stuff if you override them.
回答2:
you need to treat description as a reserved word. That is the issue you are having. You should have received a warning when you tried to have a property called description.
回答3:
For custom descriptions you are welcome to override -(NSString *)debugDescription
from NSObject Protocol.
From Apple's doc:
NSObject implements this method by calling through to the description method. Thus, by default, an object’s debug description is the same as its description. However, you can override debugDescription if you want to decouple these.
来源:https://stackoverflow.com/questions/2169252/core-data-cannot-resolve-faults-when-object-has-description-attribute