问题
I have the following problem. I have a UITableview that is powered by an NSFetchedResultsController. It should display let's say a projects, folders and files. There is no bigger hierarchy than that. So a project has several folders and those have several files. Now my table view should display those files, grouped by folders.
So i thought my fetch requests' predicate would simply be:
[NSPredicate predicateWithFormat:@"folder.project = %@", self.project];
I would then use MagicalRecord to make an NSFetchedResultsController by making something like this:
[File fetchAllGroupedBy:@"folder.name"
withPredicate:sectionPredicate
sortedBy:@"folder.name"
ascending:YES];
This basically works with one big problem... if there is no file in the folder, I wouldn't get a section for that folder (which I need!!!!)
So what I need is the tableview to also display section headers for empty folders:
Folder A
File 1
File 2
Folder B
Folder C
File 3
I could do it without the NSFetchedResultsController, but I love that it handles the inserting/deleting of rows and sections so nice and that it observes for changes...
Thx for helping, Cheers, Georg
回答1:
The solution is indeed a bit complex. I will try and explain a partial solution (no nested folders, and not section sort order support)
Model changes:
1) set the parent entity of Folder
to File
(not necessary if you use a dummy item).
2) add the BOOL field isFinal
to File
entity.
3) generate the class files for the entities.
4) in Folder.h
implement -awakeFromInsert
like this:
- (void) awakeFromInsert
{
self.isFinal = YES;
self.folder = self;//You could also fabricate a dummy item
}
FetchedResultsController:
1) set your fetch request like so:
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) initialise your FRC like so :
self.fetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:@"folder"//or @"folder.<some unique property>"
cacheName:nil];
notice that the sectionNameKeyPath
is set to folder
, and not folder.name
to support folders with the same name (if this is not required, and folder name is unique, use folder.name
)
3) in your -controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:
add at the beginning of the method:
File* file = (File*)anObject;
if (file.isFinal) {
return;
}
Table view:
1) implement:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
return [sectionInfo numberOfObjects] - 1;
}
2) implement:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
id<NSFetchedResultsSectionInfo> sec = [self.fetchedResultsController sections][section];
return [[[[sec objects] objectAtIndex:0] folder] name];
}
This should give you the basic functionality you need. To support a more complex behaviour, additional changes will be required.
来源:https://stackoverflow.com/questions/16064051/nsfetchedresultscontroller-and-getting-the-grouping-right