0

在开发 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
4

2 回答 2

1

返回具有属性名称和值的NSDictionaryResultType字典数组,而不是具有实体名称和值的字典数组。

因此,不是

[ 
  { "person" : PersonObject },
  { "person" : OtherPersonObject }
]

反而

[
  { "name" : "John", "age"  : 30 },
  { "name" : "Jane", "age"  : 20 }
]

要做你想做的事,你只需要用 . 来获取 CDPerson 实体NSManagedObjectResultsType

Person *person = fetchedObjects[0];
NSLog (@"%@", person.name);

请注意,“ Person.name”(大写的“P”)可能是错误的,因为它看起来像是类方法而不是实例方法。

于 2013-11-06T18:31:41.900 回答
0

您的fetchDistinctProperties:方法需要一个NSPropertyDescriptions 数组,但您传递的是一个 . 数组NSString

于 2013-11-07T20:59:48.957 回答