Reputation: 13787
While working on an iOS app, I am having issue resolving the properties returned from a NSFetchRequest. This is not about setting the resultType or the propertiesToFetch. It is about using the NSArray of NSDictionary instances.
Here is the actual code below, the crash is near the bottom. Thank you! BTW, the point of this code is to eventually produce a list of section headers based on hair color (that is not under hats) and then produce a list of people, without hats who have that hair color for the cells. I am not sure this is the right approach to do that, but regardless, the question stands. Thanks Again!
//
// CDHairbrained.m
//
#import "CDHairbrained.h"
#import "CDHair.h"
#import "CDPerson.h"
@implementation CDHairbrained
void defaultErrorBlock(NSError*error) {
NSLog(@"Failed to save to data store: %@", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NSLog(@" DetailedError: %@", [detailedError userInfo]);
}
} else {
NSLog(@" %@", [error userInfo]);
}
UIAlertView* av = [[UIAlertView alloc] initWithTitle:@"Booo..." message:@"MangagedObjectContext Error" delegate:nil cancelButtonTitle:@"cry" otherButtonTitles: nil];
[av show];
}
-(void) initializeObjectContext:(NSManagedObjectContext*)moc {
//NSArray<CDHairs>
for (CDHair *hair in [self fetchAllOfEntityName:@"Hair" InManagedObjectContext:moc]) {
[moc deleteObject:hair];
}
for (CDPerson *person in [self fetchAllOfEntityName:@"Person" InManagedObjectContext:moc]) {
[moc deleteObject:person];
}
//NSDictionary{color}
NSDictionary* hairdata = @{@"red": [NSEntityDescription insertNewObjectForEntityForName:@"Hair" inManagedObjectContext:moc],
@"blond":[NSEntityDescription insertNewObjectForEntityForName:@"Hair" inManagedObjectContext:moc],
@"brown":[NSEntityDescription insertNewObjectForEntityForName:@"Hair" inManagedObjectContext:moc],
@"black":[NSEntityDescription insertNewObjectForEntityForName:@"Hair" inManagedObjectContext:moc]
};
for (NSString* color in hairdata.allKeys) {
CDHair* hair = hairdata[color];
hair.color = color;
}
//NSArray<NSDictionary{name,hair,hat}>
NSArray* peopleData = @[
@{@"name":@"Stan",@"hair":hairdata[@"red"], @"hat":@"no"},
@{@"name":@"Lucy",@"hair":hairdata[@"red"], @"hat":@"no"},
@{@"name":@"Fred",@"hair":hairdata[@"black"], @"hat":@"no"},
@{@"name":@"Sherlock",@"hair":hairdata[@"black"], @"hat":@"yes"},
@{@"name":@"Barney",@"hair":hairdata[@"blond"], @"hat":@"yes"},
@{@"name":@"Dennis",@"hair":hairdata[@"blond"], @"hat":@"yes"}
];
for (NSDictionary* personData in peopleData) {
CDPerson* person =[NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:moc];
person.name = personData[@"name"];
person.hair = personData[@"hair"];
person.hat = personData[@"hat"];
}
NSError*error;
[moc save:&error];
if(error) defaultErrorBlock(error);
}
-(NSArray*) fetchAllOfEntityName:(NSString*)entityName InManagedObjectContext:(NSManagedObjectContext*) moc {
NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:entityName];
NSError* error;
NSArray* fetchResults = [moc executeFetchRequest:request error:&error];
if (fetchResults) {
return fetchResults;
}
defaultErrorBlock(error);
return nil;
}
-(NSArray*) fetchDistinctProperties:(NSArray*) propertyDescriptors
forEntityName:(NSString*) entityName
Predicate:(NSPredicate*) predicate
SortedBy:(NSArray*) sortDescriptors
InManagedObjectContext:(NSManagedObjectContext*)moc
FailureBlock:(void(^)(NSError*)) failureBlock
{
// The darnedest thing: you can't query disctict against in memory changes.
// CoreData is more trouble than it is worth.
if (moc.hasChanges) {
[NSException raise:@"FetchDistinct not return in memory changes." format:@"%@ has unsaved changes.",moc];
}
NSFetchRequest* fetchRequest = [NSFetchRequest fetchRequestWithEntityName:entityName];
fetchRequest.returnsDistinctResults = YES;
fetchRequest.propertiesToFetch = propertyDescriptors;
fetchRequest.resultType =NSDictionaryResultType;
fetchRequest.predicate=predicate;
fetchRequest.sortDescriptors = sortDescriptors;
NSError* error;
NSArray* fetchResults = [moc executeFetchRequest:fetchRequest error:&error];
if (fetchResults) {
NSLog(@"Fetched %3lu properties of %@", (unsigned long)fetchResults.count, entityName );
return fetchResults;
}
if (failureBlock)
failureBlock(error);
else
defaultErrorBlock(error);
return nil;
}
-(void) doIt:(NSManagedObjectContext*)moc {
[self initializeObjectContext:moc];
// Get a list of distinct Hair that is not underhats, to be section headers.
// And Get a list of People, with that Hair and without hats to be section cells.
//
// Expecting visibleHair to contain red, black. Not blond (none visible) Not brown, no people w/ brown hair.
// Get a distinct list of hair properties from all people without hats.
// Presume result is NSArray*<NSDictionary*{"hair":CDHair*}>
NSArray* visibleHair = [self fetchDistinctProperties:@[@"hair"]
forEntityName:@"Person"
Predicate:[NSPredicate predicateWithFormat:@"hat=='no'"]
SortedBy:nil
InManagedObjectContext:moc
FailureBlock:nil
];
// Quick Sanity Check for the debugger
NSDictionary* foundProperties = [visibleHair firstObject];
CDHair* aFoundHair = foundProperties[@"hair"];
NSLog(@"%u",aFoundHair.isFault); // <--- is nil
NSLog(@"aFoundHair: %@",aFoundHair);
NSLog(@"aFoundHair: %@",aFoundHair.color); // <------ CRASH!
// 2013-11-06 12:43:19.513 CDTest[2865:70b] -[_NSObjectID_48_0 color]: unrecognized selector sent to instance 0x8ba8670
NSLog(@"aFoundHair: %@",aFoundHair);
// Get a list of people with a particular Hair Color, who don't have hats.
NSSet* peopleWithAFoundHair = aFoundHair.people; // of CDPerson
NSArray* peopleWithAFoundHairSorted=[peopleWithAFoundHair sortedArrayUsingDescriptors:
[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]
]; // of CDPerson
NSArray*peopleWithAFoundVisibleHairSorted = [peopleWithAFoundHairSorted filteredArrayUsingPredicate:
[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings)
{
CDPerson*p=evaluatedObject;
return [p.hat compare:@"no"]==NSOrderedSame;
}]
]; // of CDPerson
CDPerson* aPerson=[peopleWithAFoundVisibleHairSorted firstObject];
NSLog(@"%@",aPerson);
}
@end
Upvotes: 0
Views: 93
Reputation: 80265
Your fetchDistinctProperties:
method needs an array of NSPropertyDescription
s but you are passing an array of NSString
.
Upvotes: 0
Reputation: 80265
The NSDictionaryResultType
returns an array of dictionaries with property names and values, not an array of dictionaries with entity names and values.
Thus, not:
[
{ "person" : PersonObject },
{ "person" : OtherPersonObject }
]
but rather
[
{ "name" : "John", "age" : 30 },
{ "name" : "Jane", "age" : 20 }
]
To do what you want, you need to just fetch the CDPerson entity with NSManagedObjectResultsType
.
Person *person = fetchedObjects[0];
NSLog (@"%@", person.name);
Note that "Person.name
" (with a capital "P") is probably wrong, as it looks like a class method rather than an instance method.
Upvotes: 1