NSFetchedResultsController:如何从实体的to-many关系中获取sectionName

我有一个核心数据模型: ParentObject <--->> ChildObject

ParentObjectChildObject 都具有 levelNumber 属性:

typedef enum {
    Primary,
    Secondary,
    Tertiary
} LevelNumber;

我还有一个方法可以在ParentObject和childObject中将级别编号从int转换为string:

-(void) levelString
{
    switch(self.levelNumber)
   {
      case Primary: return @"Primary";
      case Secondary: return @"Secondary";
      case Tertiary: return @"Tertiary";
      default: return @"Error";

   }

}

现在我在tableview中有一个FetchedResultsController,列出了 ParentObject . 我想在节名中得到的是:

  • If the ParentObject is Secondary or Tertiary, show the section name as Secondary or Tertiary.

  • If the ParentObject is Primary but any of the ChildObjects are Secondary or Tertiary, show the section name as Secondary or Tertiary.

  • If the ParentObject and all the ChildObjects are Primary, show section name as Primary

如果我只需要查看 ParentObjectlevelNumber 就会非常简单,如下所示 -

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"ParentObject"];
NSSortDescriptor *levelNumSD = [NSSortDescriptor sortDescriptorWithKey:@"levelNumber" ascending:YES];
request.sortDescriptors = [NSArray arrayWithObjects:levelNumSD, nil];

self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                    managedObjectContext:myContext
                                                                      sectionNameKeyPath:@"levelString"
                                                                               cacheName:nil];

我知道FRC中的限制是SortDescriptor的结果应该以与显示喜欢的顺序相同的顺序返回结果 . 我如何在这里加入 ChildObject 检查 . 它会是一种新的SortDescriptor,还是其他什么?

回答(1)

2 years ago

看一下Apple的示例代码DateSectionTitles,它解释了如何将日期作为部分,以及您在几乎适用于您的情况 . 您在 titleForSection 中管理的字符串的实际显示,但您在数据库中保留了"primitive"和可排序的属性,称为 sectionIdentifier .

在您的特定情况下,部分标识符将类似于 levelNumber ,并且只需返回所有子项的最高 levelNumber 即可计算 .

模式如下:

-(NSString*)sectionIdentifier {
   [self willAccessValueForKey:@"sectionIdentifier"];
   NSNumber *tmp = [self primitiveSectionIdentifier];
   [self didAccessValueForKey:@"sectionIdentifier"];

   if (!tmp) {
      NSNumber *childrenMax = [self valueForKeyPath:@"@max.children.levelNumber"];
      tmp = childrenMax.intValue > self.levelNumber.intValue ?
            childrenMax : self.levelNumber;
      [self setPrimitiveSectionIdentifier:tmp];
   }

   return tmp;
}

如果实体发生变化,请不要忘记重置它 .

-(void)setLevelNumber:(NSNumber)newNumber {
   [self willChangeValueForKey:@"levelNumber"];
   [self setPrimitiveLevelNumber:newNumber];
   [self willChangeValueForKey:@"levelNumber"];

   [self setPrimitiveSectionIdentifier:nil];
}

最后,确保在相关数据更改时它变为无效:

+(NSSet*) keyPathsForValuesAffectingSectionIdentifier {
   return [NSSet setWithObject:@"levelNumber"];
}

要监视任何孩子的 levelNumber 中的更改,父母会监听 NSManagedObjectContextDidSaveNotification 并查看其中的任何子女是否在该保存中 .