views:

740

answers:

6

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
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 one 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?

+1  A: 

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.

St3fan
+1 Good point. I tested some here too and it actually does differently depending on selected language in Settings. Think I have the sorting figured out now. But still I can not get it to draw correctly...
epatel
+1  A: 

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?

gerry3
+1 Yup, basing my solution of your recommendations there, thanks! I try to trust Core Data as much as possible. Will look into subclassing the NSFetchedResultsController, first try failed
epatel
This is not subclassing, it is a method that you can implement in your table view delegate.
gerry3
Thought it was a method (sectionIndexTitleForSectionName:) on the controller when reading the docs?!
epatel
Oops, you are correct. Sorry about that.
gerry3
+3  A: 

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)

St3fan
+1 for the research and interest. But I think I have nailed the sorting now. I use `localizedCaseInsensitiveCompare:` for a sort descriptor to the fetched result controller, which will keep order as the language setting on the device. But, index titles etc are handled by CoreData as gerry3 described here http://stackoverflow.com/questions/1741093/how-to-use-the-first-character-as-a-section-name/1741131#1741131
epatel
+1  A: 

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.

kimsnarf
Have to try this...
epatel
+1  A: 

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.

macttrek
This sounds promising. Have to try...if I only can find the project files again ;)
epatel
A: 

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

Nabonassar