问题
I am trying to implement a Core Data backed UITableView that supports indexing (eg: the characters that appear down the side, and the section headers that go with them). I have no problems at all implementing this without Core Data using:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
I also have no problem implementing a UITableView that is backed by Core Data without using the indexing.
What I am trying to figure out is how to elegantly combine the two? Obviously once you index and re-section content, you can no longer use the standard NSFetchedResultsController to retrieve things at a given index path. So I am storing my index letters in an NSArray and my indexed content in an NSDictionary. This all works fine for display, but I have some real headaches when it comes to adding and deleting rows, specifically how to properly implement these methods:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller;
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath;
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type;
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller;
Because the index paths it's returning me have no correlation with the ones in core data. I got add working by simply rebuilding my index NSArray and NSDictionary when the user adds a row, but doing the same when they delete one crashes the whole application.
Is there a simple pattern/example I'm missing here to make all this work properly?
Edit: Just to clarify I know that the NSFetchedResultsController does this out of the box, but what I want is to replicate the functionality like the Contacts app, where the index is the first letter of the first name of the person.
回答1:
You should use your CoreData NSFetchedResultsController to get your sections/indexes.
You can specify the section key in the fetch request (I think it has to match the first sort key):
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
initWithKey:@"name" // this key defines the sort
ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext
sectionNameKeyPath:@"name" // this key defines the sections
cacheName:@"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
Then, you can get the section names like this:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo name];
}
And the section indexes are here:
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
[sectionInfo indexTitle]; // this is the index
Changes to the content just indicate that the table needs to be updated:
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView reloadData];
}
UPDATE
This only works for the index and fast index scrolling, not for the section headers.
See this answer to "How to use the first character as a section name" for more information and details on how to implement first letters for section headers as well as the index.
来源:https://stackoverflow.com/questions/1599204/core-data-backed-uitableview-with-indexing