I have added a section list for a simple Core Data iPhone app.
I followed this so question to create it - How to use the first character as a section name but my list also contain items starting with characters outside A-Z, specially Å,Ä and Ö used here in Sweden.
The problem now is that when the table view shows the section list the three last characters are drawn wrong. See image below
- alt text http://img.skitch.com/20100130-jkt6e55pgyjwptgix1q8mwt7md.jpg
It seems like my best option right now is to let those items be sorted under 'Z'
if ([letter isEqual:@"Å"] ||
[letter isEqual:@"Ä"] ||
[letter isEqual:@"Ö"])
letter = @"Z";
Someone that have figured this on开发者_开发技巧e out?
And while I'm at it... 'Å', 'Ä' and 'Ö' should be sorted in that order but are sorted as 'Ä', 'Å' and 'Ö' by Core Data NSSortDescriptor
. I have tried to set set the selector to localizedCaseInsensitiveCompare:
but that gives a out of order section name 'Ä. Objects must be sorted by section name'
error. Seen that too?
So I could not let go of this one and found the following:
What you need to do in this case is called 'Unicode Normalization Form D'. It is more explained in http://unicode.org/reports/tr15/ (warning, long and dry document)
Here is a function that does the decomposition and then filters out all diacritics. You can use this to convert Äpple to Apple and then use the first letter to build an index.
- (NSString*) decomposeAndFilterString: (NSString*) string
{
NSMutableString *decomposedString = [[string decomposedStringWithCanonicalMapping] mutableCopy];
NSCharacterSet *nonBaseSet = [NSCharacterSet nonBaseCharacterSet];
NSRange range = NSMakeRange([decomposedString length], 0);
while (range.location > 0) {
range = [decomposedString rangeOfCharacterFromSet:nonBaseSet
options:NSBackwardsSearch range:NSMakeRange(0, range.location)];
if (range.length == 0) {
break;
}
[decomposedString deleteCharactersInRange:range];
}
return [decomposedString autorelease];
}
(I found this code on a mailing list, forgot the source, but I took it and fixed it up a little)
I am experiencing the same issue reported in the original question, i.e. extended characters (outside Unicode page 0) not properly displayed in the index bar.
Although I seem to feed NSFetchedResultsController with correct single unicode character strings, what I get in return accessing the 'sectionIndexTitles' property are those same characters with the high byte set to 0; for example character \u30a2 (KATAKANA LETTER A) becomes \u00a2 (CENT SIGN).
I am not sure whether this is a bug in the method sectionIndexTitleForSectionName: of NSFetchedResultsController or my own fault somewhere else, however my workaround consists in overriding it and performing what the documentation says it does internally:
- (NSString *)sectionIndexTitleForSectionName:(NSString *)sectionName
{
NSString *outName;
if ( [sectionName length] )
outName = [[sectionName substringToIndex:1] uppercaseString];
else
outName = [super sectionIndexTitleForSectionName:sectionName];
return outName;
}
This produces the expected output.
Just adding this in my controller solved the original problem for me
- (NSString *)controller:(NSFetchedResultsController *)controller sectionIndexTitleForSectionName:(NSString *)sectionName {
return sectionName;}
Å, Ä and Ö displays properly in the list
When I encounter situation like this, the first thing I ask myself is 'what does Apple do'.
As an experiment I just added 'Joe Äpple' to my iPhone address book and he shows up under the plain A. I think that makes a lot of sense.
So instead of throwing them under Z or Ä you should do the same. There must be some way to get the 'base' letter of a unicode character for the grouping.
You can use UTF-8 encoding
const char *cLetter = (const char *)[ tmp cStringUsingEncoding:NSUTF8StringEncoding];
NSString *original = [NSString stringWithCString:cLetter encoding:NSUTF8StringEncoding];
Did you follow my answer to that other question?
I am doing some tests (refetching my objects) and seeing odd intermittent behavior. It definitely sorts them correctly (with 'Å' right after 'A', but before 'Ä') sometimes. Other times it puts the characters outside of A-Z all at the end (after 'Z') even though I didn't do anything special.
Also, I noticed that 'Å' is drawn correctly if you return its lowercase form. Have you tried overriding sectionIndexTitleForSectionName:
to keep the order, but change the drawn character?
Did you ever solve this issue?
I've been able to get the section title index to display correctly by implementing sectionIndexTitlesForTableView: to build my own array of section titles:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
NSMutableArray *indexKeys = [NSMutableArray arrayWithCapacity:30];
NSArray *fetchedResults = [fetchedResultsController fetchedObjects];
NSString *currKey = @"DEFAULT";
for (NSManagedObject *managedObject in fetchedResults) {
NSString *indexKey = [managedObject valueForKey:@"indexKey"];
if (![indexKey isEqualToString:currKey]) {
[indexKeys addObject:indexKey];
currKey = indexKey;
}
}
return indexKeys;
}
Here, indexKey is the first letter of the name.
However, this creates one of two issues in sectionForSectionIndexTitle: instead:
If I simply return the index for the section this is now the unsorted index and no longer corresponds with the sort order in the fetchResultController:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return index;
}
Alternatively, If I pass on the call to the fetchedResultsController it breaks on the non-US index titles because these are no longer the weird characters used by the fetchedResultsController:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
}
The latter code generates an error of the following kind when navigating to the "Ø" index title:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Index title at 24 is not equal to 'Ø''
A workaround for this is to translate the offending characters back to their weird selves:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
if ([title isEqualToString:@"Æ"]) {
title = @"\u2206";
} else if ([title isEqualToString:@"Ø"]) {
title = @"\u0178";
} else if ([title isEqualToString:@"Å"]) {
title = @"\u2248";
}
return [fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
}
You can find the Unicode values in the debugger with the action "Print Description to Console".
However, the good solution would be to figure out why this weird encoding happens and prevent it.
精彩评论