I'm rewriting an old obj-c project in swift that has a tableView with a sectionIndex
I've set a predicate so it only returns objects with the same country attribute
I want to make the section index based on the first letter of the country attribute
in obj-c i created the fetchedResultsController like this
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:@"name.stringGroupByFirstInitial" cacheName:nil];
and i had an extension on NSString
@implementation NSString (Indexing)
- (NSString *)stringGroupByFirstInitial {
if (!self.length || self.length == 1)
return self;
return [self substringToIndex:1];
}
this worked fine in conjunction with the two methods
- (NSArray *) sectionIndexTitlesForTableView: (UITableView *) tableView{
return [self.fetchedResultsController sectionIndexTitles];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index{
return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
}
In swift I tried to create a similar extension, with snappier name :)
extension String {
func firstCharacter()-> String {
let startIndex = self.startIndex
let first = self[...startIndex]
return String(first)
}
}
which works fine in a playground returning the string of the first character of any string you call it on.
but using a similar approach creating the fetchedResultsController, in swift, ...
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: (dataModel?.container.viewContext)!,
sectionNameKeyPath: "country.firstCharacter()",
cacheName: nil)
...causes an exception. heres the console log
2018-02-23 11:41:20.762650-0800 Splash[5287:459654] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]: this class is not key value coding-compliant for the key firstCharacter().'
Any suggestions as the correct way to approach this would be appreciated
This is not a duplicate of the question suggested as this is specifically related to how to achieve this in Swift. I have added the simple correct way to achieve this in Obj -c to the other question
Add a function to your DiveSite
class to return the first letter of the country
:
@objc func countryFirstCharacter() -> String {
let startIndex = country.startIndex
let first = country[...startIndex]
return String(first)
}
Then use that function name (without the ()
) as the sectionNameKeyPath
:
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: (dataModel?.container.viewContext)!,
sectionNameKeyPath: "countryFirstCharacter",
cacheName: nil)
Note that the @objc
is necessary here in order to make the (Swift) function visible to the (Objective-C) FRC. (Sadly you can't just add @objc
to your extension of String.)