I am loading a list of objects from CoreData like this:
- (NSMutableArray *)loadAllPoisFromCache:(BOOL)includeCustom {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"PointOfInterest" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]
initWithKey:@"sortOrder" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sort]];
[sort release];
if(!includeCustom) {
NSPredicate开发者_如何转开发 *predicate = [NSPredicate predicateWithFormat:@"(custom == %i)",NO];
[request setPredicate:predicate];
}
[request setEntity:entity];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
[request release];
return mutableFetchResults;
}
The "PointOfInterest" entity is a COMPPointOfInterest and it has a relationship to an entity "Location" which is a COMPLocationEntity.
I then loop through the results:
NSMutableArray *mutableFetchResults = [self loadAllPoisFromCache:YES];
if (mutableFetchResults != nil && [mutableFetchResults count] > 0) {
NSLog(@"NOTIF_PoisLoaded with data from cache");
for (COMPPointOfInterest *aPoi in mutableFetchResults) {
COMPLocationEntity *locBeforePrintingOutPoi = aPoi.locationEntity;
NSLog(@"Loc class before printing out parent POI = %@", [locBeforePrintingOutPoi class]);
NSLog(@"Loaded POI %@ from cache %@ and location %@", aPoi.poiId, [aPoi class], [locBeforePrintingOutPoi class]);
NSLog(@"Loaded POI from cache %@", aPoi);
COMPLocationEntity *locAfterPrintingOutPoi = aPoi.locationEntity;
NSLog(@"Loc class refetched from parent POI after printing out POI = %@", [locAfterPrintingOutPoi class]);
NSNumber *lat2 = locAfterPrintingOutPoi.latitude;
NSLog(@"Lat from refetched loc %@", lat2);
// crash on next line!
NSNumber *lat = locBeforePrintingOutPoi.latitude;
NSLog(@"Lat %@", lat);
}
Now, this is where I'm stuck, if you run this, the output is as follows:
2011-01-24 16:35:41.063 NEC Companion[11959:207] NOTIF_PoisLoaded with data from cache
2011-01-24 16:35:41.064 NEC Companion[11959:207] Loc class before printing out parent POI = _NSObjectID_48_1
2011-01-24 16:35:41.068 NEC Companion[11959:207] Loaded POI 1 from cache COMPPointOfInterest and location _NSObjectID_48_1
2011-01-24 16:35:41.069 NEC Companion[11959:207] Loaded POI from cache (entity: PointOfInterest; id: 0xae19110 ; data: { cacheDate = "2011-01-24 16:09:26 +0000"; custom = 0; locationEntity = "0xae18ff0 "; logoUrl = "http://192.168.37.213/companion/images/mapicons/es"; poiId = 1; sortOrder = 0; })
2011-01-24 16:35:41.071 NEC Companion[11959:207] Loc class refetched from parent POI after printing out POI = COMPLocationEntity
2011-01-24 16:35:41.072 NEC Companion[11959:207] Lat from refetched loc 52.460118
2011-01-24 16:35:41.072 NEC Companion[11959:207] -[_NSObjectID_48_1 latitude]: unrecognized selector sent to instance 0xae18ff0
The crux of my problem is that if I grab the "locationEntity" attribute from the POI immediately when I start iterating through the list, the class comes out as _NSObjectID_48_1, I then do an NSLog(@"Loaded POI from cache %@", aPoi); and following that I get the "locationEntity" attribute again and I end up with the correct COMPLocationEntity class!
So it looks like calling the description method is doing something to fully instantiate the POI correctly...but what?
Any help much appreciated.
Right, looks like I've solved it. My problem was indeed that the locationEntity was a relationship and adding the following to my query causes the object to load correctly with my location relationship fully populated.
[request setRelationshipKeyPathsForPrefetching: [NSArray arrayWithObject:@"locationEntity"]];
See http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSFetchRequest_Class/NSFetchRequest.html
It looks like it's faulting - CoreData isn't getting the data until you ask for it specifically.
You have specified not to fault the properties of each aPoi in your results when you created your fetch request. This means that it's got all the properties of the COMPointOfInterest object.
However, this doesn't mean that all it's relationship's objects are not faulted - your COMPLocationEntity objects are (I assume) a relationship. CoreData won't get these until they are specifically asked for and will mark them as faults until then. Hence getting a very odd object name. When you ask for a COMPLocationEntity's property (in this case the description*), the fault fires and the real COMPLocationEntity object is loaded.
The fault is fired in this line :
NSLog(@"Loaded POI from cache %@", aPoi);
Core Data needs some real data to output your aPoi object so goes and gets it from the database and makes the COMPLocationEntity object.
Hope that helps.
*Usually, calling description on a NSManagedObject won't cause a fault (it's done that way deliberately). Have you overridden the description method in your class to output something more useful? If so, you're causing the fault to be triggered yourself!
精彩评论