We're trying to use an NSFetchedResultsController
to return people names and populate a UITableView
in sorted order, using localizedCompare:
. We're also trying to provide a section index in the UI (the right column of first characters of each section). We provide the NSFetchedResultsController
with a selector on our entity which provides the section each entity should belong to (specifically, the first character of the person's name, capitalized).
When dealing with people names which utilize Unicode code points we've run into an issue. NSFetchedResultsController
complains the entities are not sorted by section.
Specifically:
reason=The fetched object at index 103 has an out of order section name 'Ø. Objects must be sorted by section name'}, {
reason = "The fetched object at index 103 has an out of order section name '\U00d8. Objects must be sorted by section name'";
The issue appears to be that the comparison value returned by localizedCompare:
is different for the whole "word" versus the leading character.
The following tests pass though I would expect consistent comparison results between ("Ø" and "O") vs. ("Østerhus" and "Osypowicz").
- (void)testLocalizedSortOrder300
{
NSString *str1 = @"Osowski";
NSString *str2 = @"Østerhus";
NSString *str3 = @"Osypowicz";
NSString *letter1 = @"O";
NSString *letter2 = @"Ø";
//localizedCompare:
//"Osowski" < "Østerhus"
NSComparisonResult res = [str1 localizedCompare:str2];
XCTAssertTrue(res == NSOrderedAscending, @"(localizedCompare:) Expected '%@' and '%@' to be NSOrderedAscending, but got %@", str1, str2, res == NSOrderedSame ? @"NSOrderedSame" : @"NSOrderedDescending");
//"Østerhus" < "Osypowicz"
res = [str2 localizedCompare:str3];
XCTAssertTrue(res == NSOrderedAscending, @"(localizedCompare:) Expected '%@' and '%@' to be NSOrderedAscending, but got %@", str2, str3, res == NSOrderedSame ? @"NSOrderedSame" : @"NSOrderedDescending");
//"O" < "Ø"
res = [letter1 localizedCompare:letter2];
XCTAssertTrue(res == NSOrderedAscending, @"(localizedCompare:) Expected '%@' and '%@' to be NSOrderedAscending, but got %@", letter1, letter2, res == NSOrderedSame ? @"NSOrderedSame" : @"NSOrderedDescending");
}
So, the question ultimately is, given a person name (or any other string) which utilize Unicode code points, how do we properly (in a localized manner) return a section name which will correspond with the sort order as dictated by localizedCompare:
?
Additionally, what's going on with the localizedCompare:
apparently treating "Ø" and "O" as NSOrderedSame
when followed by additional characters?