如何使用NSFetchRequest返回的属性?

时间:2013-11-06 18:01:58

标签: ios objective-c core-data

在处理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

2 个答案:

答案 0 :(得分:1)

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

因此,

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

而是

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

要执行您想要的操作,您只需使用NSManagedObjectResultsType获取CDPerson实体。

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

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

答案 1 :(得分:0)

您的fetchDistinctProperties:方法需要NSPropertyDescription个数组,但您传递的数组为NSString