【问题标题】:NSFetchedResultsController: How to get sectionName from to-many relationship of the entityNSFetchedResultsController:如何从实体的多对多关系中获取sectionName
【发布时间】:2013-06-29 08:42:59
【问题描述】:

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

ParentObject 和 ChildObject 都有一个属性 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";

   }

}

现在我在一个列出ParentObject 的tableview 中有一个FetchedResultsController。 我想在部分名称中获得的是:

  • 如果ParentObject 是Secondary 或Tertiary,则显示该部分 命名为Secondary 或Tertiary。
  • 如果ParentObject 是Primary,但任何ChildObjects 是Secondary 或Tertiary,则将部分名称显示为Secondary 或Tertiary。李>
  • 如果ParentObject 和所有ChildObjects 都是Primary,则显示部分名称为Primary

如果我只需要查看ParentObject 的levelNumber 就很简单了,如下所示-

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,还是别的什么?

【问题讨论】:

  • IMO 在您的父对象模型中有一个单独的属性 sectionLevelNumber。
  • devforums.apple.com/message/682121#682121 这可能对你有帮助。
  • @Bala 如果我理解正确,属性sectionLevelNumber 本身不会存储任何值,但它的getter 实际上会查看ParentObject 的levelNumber 以及所有ChildObjects 并查看返回哪个级别。这将是一个问题,因为在 FRC 的第一次提取中,它希望将值存储在数据库中,而不是在运行时派生。
  • 蒙迪已经解释清楚了

标签: ios core-data nssortdescriptor nsfetchedresultscontroller


【解决方案1】:

查看 Apple 的示例代码 DateSectionTitles,它解释了如何将日期作为部分,并且您也可以将其用于您的案例。您在titleForSection 中管理的字符串的实际显示,但您在数据库中保留了一个“原始”且可排序的属性,称为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 并查看其是否有任何子级在该保存中。

【讨论】:

  • 好答案!不过我有一些问题:1)如果在keyPathsForValuesAffectingSectionIdentifier中注册了“levelNumber”,是否仍然需要覆盖setLevelNumber? 2) “@children”中的@ 是错字还是故意的? 3) 更改 ChildObject 的 levelNumber 是否真的会使相关 ParentObject 的 sectionIdentifier 无效?也许在 ChildObject 中覆盖 setLevelNumber 会很有用。谢谢!
  • 1) 是的,这是一种很好的做法,没有任何害处。 2)错字。更正了它。 3)原则上你是对的,但我会担心实体的相互依赖性。理想情况下,您只将此功能封装到父实体中。
  • 但是使用您当前的代码,修改 ChildObject 的 levelNumber 不会更新相关 ParentObject 的 sectionIdentifier。因为 keyPathsForValuesAffectingSectionIdentifier 中的“children”只会影响子对象对“children”关系的添加/删除,但不会修改已经相关的子对象(除非我弄错了)。
  • 没错。毕竟,您将不得不去儿童实体。最好覆盖setLevelNumber。
  • 这并不完全有效。 request.sortDescriptors 应该使用什么?如果我只使用parentObject 的levelNumber。它给出了错误:CoreData: error: (NSFetchedResultsController) The fetched object at index 2 has an out of order section name '2(Secondary) Objects must be sorted by section name'。例如,当所有ParentObject 都是Primary,但第二个ParentObject 的ChildObject 之一是Secondary 时,就会发生这种情况。我不能使用sectionIdentifier 进行排序,因为它是一个瞬态属性。
猜你喜欢
  • 2015-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-25
  • 1970-01-01
  • 1970-01-01
  • 2014-05-09
  • 1970-01-01
相关资源
最近更新 更多