NSFetchedResultsController 并正确分组
Posted
技术标签:
【中文标题】NSFetchedResultsController 并正确分组【英文标题】:NSFetchedResultsController and getting the grouping right 【发布时间】:2013-04-17 15:24:48 【问题描述】:我有以下问题。我有一个由 NSFetchedResultsController 提供支持的 UITableview。 它应该显示一个项目、文件夹和文件。没有比这更大的等级制度了。所以一个项目有几个文件夹,那些有几个文件。 现在我的表格视图应该显示这些文件,按文件夹分组。
所以我认为我的获取请求的谓词只是:
[NSPredicate predicateWithFormat:@"folder.project = %@", self.project];
然后我会使用 MagicalRecord 来制作一个 NSFetchedResultsController,方法如下:
[File fetchAllGroupedBy:@"folder.name"
withPredicate:sectionPredicate
sortedBy:@"folder.name"
ascending:YES];
这基本上适用于一个大问题......如果文件夹中没有文件,我不会得到该文件夹的部分(我需要它!!!!)
所以我需要的是 tableview 来显示空文件夹的部分标题:
Folder A
File 1
File 2
Folder B
Folder C
File 3
我可以在没有 NSFetchedResultsController 的情况下做到这一点,但我喜欢它很好地处理行和节的插入/删除,并且它可以观察变化......
感谢您的帮助, 干杯, 乔治
【问题讨论】:
我不认为有一个简单(甚至中等复杂)的解决方案。 FRC 不会创建空部分。您将不得不修改表视图数据源方法,但随后 FRC 索引路径和表视图索引路径不再同步,这使得 FRC 委托方法(didChangeObject,...)变得复杂。 【参考方案1】:解决方案确实有点复杂。我将尝试解释部分解决方案(无嵌套文件夹,不支持部分排序顺序)
模型更改:
1) 将Folder
的父实体设置为File
(如果使用虚拟项目则不需要)。
2) 将 BOOL 字段 isFinal
添加到 File
实体。
3) 为实体生成类文件。
4) 在Folder.h
中像这样实现-awakeFromInsert
:
- (void) awakeFromInsert
self.isFinal = YES;
self.folder = self;//You could also fabricate a dummy item
FetchedResultsController: 1) 像这样设置您的获取请求:
NSFetchRequest* request = [[NSFetchRequest alloc] initWithEntityName:@"File"];
NSSortDescriptor* terminalSort = [NSSortDescriptor sortDescriptorWithKey:@"isFinal" ascending:YES];
NSSortDescriptor* nameSort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
[request setSortDescriptors:@[terminalSort,nameSort]];
[request setPredicate:[NSPredicate predicateWithFormat:@"folder.project == %@",project]]
//Any additional settings
2) 像这样初始化您的 FRC:
self.fetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:@"folder"//or @"folder.<some unique property>"
cacheName:nil];
注意sectionNameKeyPath
设置为folder
,而不是folder.name
以支持同名文件夹(如果不需要,并且文件夹名称是唯一的,请使用folder.name
)
3) 在你的-controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:
方法的开头添加:
File* file = (File*)anObject;
if (file.isFinal)
return;
表格视图: 1) 实施:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
return [sectionInfo numberOfObjects] - 1;
2) 实施:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
id<NSFetchedResultsSectionInfo> sec = [self.fetchedResultsController sections][section];
return [[[[sec objects] objectAtIndex:0] folder] name];
这应该为您提供所需的基本功能。 为了支持更复杂的行为,需要进行额外的更改。
【讨论】:
嗨,丹,感谢您回答我的问题!所以基本上你为每个文件夹插入一个虚拟项目,这是他自己?无法对我的部分进行排序是很糟糕的......不可能改变它,会有吗? 正如我所说,为了按文件夹名称对部分进行排序,文件夹名称必须是唯一的,您sectionNameKeyPath
将是 folder.name
,或者您需要创建一个唯一的一个文件夹的属性,以匹配您所需的排序顺序并使其成为您的sectionNameKeyPath
啊,好吧...好吧,我确实尝试了这个解决方案,并会检查我是否喜欢它。我必须更改我的数据模型以便 ViewController 可以按照他想要的方式显示数据这一事实对我来说似乎并不好。我有一个可以使用多个 FRC 的 TableViewController 版本,我想我现在会坚持下去。当 name:NSManagedObjectContextObjectsDidChangeNotification 被触发时,我只是更新那些 FRC。我以这种方式失去了我的动画,但我会想出一些办法。但这样我就不必弄乱我的数据模型了。无论如何,非常感谢您的帮助!以上是关于NSFetchedResultsController 并正确分组的主要内容,如果未能解决你的问题,请参考以下文章