NSFetchedResultsController:如何从实体的多对多关系中获取sectionName
Posted
技术标签:
【中文标题】NSFetchedResultsController:如何从实体的多对多关系中获取sectionName【英文标题】:NSFetchedResultsController: How to get sectionName from to-many relationship of the entity 【发布时间】: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 的第一次提取中,它希望将值存储在数据库中,而不是在运行时派生。
蒙迪已经解释清楚了
【参考方案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
进行排序,因为它是一个瞬态属性。以上是关于NSFetchedResultsController:如何从实体的多对多关系中获取sectionName的主要内容,如果未能解决你的问题,请参考以下文章