Reputation: 682
How can I index a NSFetchedResultsController
so that I can implement an A-Z index on a tableview.
I see in the initializer I can do sectionNameKeyPath
but this just places unique objects in their own section.
Here is what I have for my NSFetchedResultsController
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil) {
return __fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Customer" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"name" cacheName:@"Customer"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
return __fetchedResultsController;
}
Upvotes: 4
Views: 2667
Reputation: 9505
correct version (ios 7.1 to 8.3):
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [NSArray arrayWithObjects:@"A",@"B",@"C",@"D",@"E",@"F",@"G",@"H",@"I",@"J",@"K",@"L",@"M",@"N",@"O",@"P",@"Q",@"R",@"S",@"T",@"U",@"V",@"W",@"X",@"Y",@"Z",@"#",nil];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
NSInteger section = 0;
for (id <NSFetchedResultsSectionInfo> sectionInfo in [_fetchedResultsController sections])
{
if ([sectionInfo.indexTitle compare:title] >= 0)
{
break;
}
section++;
}
return section;
}
Upvotes: 0
Reputation: 712
@Harris' answer will show the whole alphabet on the side of the table. Unfortunately, if you then tap one of the letters that does actually have a corresponding section, you crash with something like:
Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'Index title at 3 is not equal to 'K''
Upvotes: 1
Reputation: 8610
If you want to have the letters A-Z on the side (even though you don't have sections for every single letter) this will do it:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [NSArray arrayWithObjects:@"A",@"B",@"C",@"D",@"E",@"F",@"G",@"H",@"I",@"J",@"K",@"L",@"M",@"N",@"O",@"P",@"Q",@"R",@"S",@"T",@"U",@"V",@"W",@"X",@"Y",@"Z",@"#",nil];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
index = 0;
for(id sectionInfo in [_fetchedResultsController sections]){
if ([[[sectionInfo name] uppercaseString] isEqualToString:title]){
break;
}
index++;
}
if (index>=[_fetchedResultsController sections].count){
return -1;
}
return [_fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
}
Upvotes: 0
Reputation: 90117
implement sectionIndexTitlesForTableView:
like this:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [self.fetchedResultsController sectionIndexTitles];
}
this will give you those indexes on the right side of the tableView.
If you want your sections to have names like A, B, C, D etc. you have to implement a method that returns the first letter for your object.
something like this:
- (NSString *)firstLetter {
[self willAccessValueForKey:@"firstLetter"];
NSString *firstLetter = [[[self name] substringToIndex:1] uppercaseString];
[self didAccessValueForKey:@"firstLetter"];
return firstLetter;
}
This goes into the custom subClass of your coredata entity.
Then add a transient attribute named firstLetter
to your core data entity and replace the sectionNameKeyPath in the NSFetchedResultsController init with firstLetter
Upvotes: 13