在开发 iOS 应用程序时,我在解析从 NSFetchRequest 返回的属性时遇到问题。这与设置 resultType 或 propertiesToFetch 无关。它是关于使用 NSDictionary 实例的 NSArray。
这是下面的实际代码,崩溃接近底部。谢谢!顺便说一句,这段代码的重点是最终生成一个基于头发颜色(不在帽子下)的部分标题列表,然后生成一个人员列表,没有帽子的单元格具有该头发颜色。我不确定这是做到这一点的正确方法,但无论如何,问题仍然存在。再次感谢!
//
// 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