iPhone contacts app styled indexed table view implementation

点点圈 提交于 2019-12-03 09:15:38

This is a really inefficient first-pass at this problem, which I am going to rewrite eventually. But hopefully this will help you.

The idea of this is to "guarantee" getting a real table section index back when tapping a "standard" section index view. A standard section index view should have a magnifying lens icon for search, a hash mark (#) for non-alphabetical sections, and letters A through Z for alphabetical sections.

This standard view is presented regardless of how many real sections there are, or what they are made of.

Ultimately, this code maps section view indices to real-existing alphabetic section name paths in the fetched results controller, or to real-existing non-alphabetic (numerical) sections, or to the search field in the table header.

The user will only occasionally recreate the section index mapping array (_idxArray) on each touch of the section index, but recreating the array on each touch is obviously inefficient and could be tweaked to cache pre-calculated results.

There are a lot of places to start tightening this up: I could make the sectionIndexTitleLetters static string all uppercase from the start, for example. It's fast enough on a 3GS phone, though, so I haven't revisited this recently.

In the header:

static NSString *sectionIndexTitleLetters = @"abcdefghijklmnopqrstuvwxyz";

In the implementation of the table view data source:

- (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tv {
    if (tv != searchDisplayController.searchResultsTableView) {
        NSMutableArray *_indexArray = [NSMutableArray arrayWithCapacity:([sectionIndexTitleLetters length]+2)];

        [_indexArray addObject:@"{search}"];
        [_indexArray addObject:@"#"];

        for (unsigned int _charIdx = 0; _charIdx < [sectionIndexTitleLetters length]; _charIdx++) {
            char _indexChar[2] = { toupper([sectionIndexTitleLetters characterAtIndex:_charIdx]), '\0'};
            [_indexArray addObject:[NSString stringWithCString:_indexChar encoding:NSUTF8StringEncoding]];
        }

        return _indexArray;
    }
    return nil;
}

- (NSInteger) tableView:(UITableView *)tv sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
    if (tv != searchDisplayController.searchResultsTableView) {
        if (index == 0) {
            //
            // This is the search bar "section"
            //
            [currentTableView scrollRectToVisible:[[currentTableView tableHeaderView] bounds] animated:YES];
            return -1;
        }
        else if (index == 1) {
            //
            // This is the "#" section, which covers non-alphabetic section headers (e.g. digits 0-9)
            //
            return 0;
        }
        else {
            //
            // This is a bit more involved because the section index array may contain indices that do not exist in the 
            // fetched results controller's sections->name info.
            //
            // What we are doing here is building a "fake-index" array that will return a real section index regardless of 
            // whether the section index title being touched exists or not. 
            //
            // The fake array will be of length of the section index title array, and each index will contain an unsigned 
            // integer from 1 to {numOfRealSections}. 
            //
            // The value this array returns will be "nearest" to the real section that is in the fetched results controller.
            //

            NSUInteger _alphabeticIndex = index-2;

            unsigned int _idxArray[26];
            for (unsigned int _initIdx = 0; _initIdx < [sectionIndexTitleLetters length]; _initIdx++) {
                _idxArray[_initIdx] = [[fetchedResultsController sections] count] - 1;
            }

            unsigned int _previousChunkIdx = 0;
            NSNumberFormatter *_numberFormatter = [[NSNumberFormatter alloc] init];
            NSLocale *_enUSLocale = [[NSLocale alloc] initWithLocaleIdentifier: @"en_US"];
            [_numberFormatter setLocale:_enUSLocale];
            [_enUSLocale release];

            for (unsigned int _sectionIdx = 0; _sectionIdx < [[fetchedResultsController sections] count]; _sectionIdx++) {
                NSString *_sectionTitle = [[[fetchedResultsController sections] objectAtIndex:_sectionIdx] name];
                if (![_numberFormatter numberFromString:_sectionTitle]) {
                    // what's the index of the _sectionTitle across sectionIndexTitleLetters?
                    for (unsigned int _titleCharIdx = 0; _titleCharIdx < [sectionIndexTitleLetters length]; _titleCharIdx++) {
                        NSString *_titleCharStr = [[sectionIndexTitleLetters substringWithRange:NSMakeRange(_titleCharIdx, 1)] uppercaseString];
                        if ([_titleCharStr isEqualToString:_sectionTitle]) {
                            // put a chunk of _sectionIdx into _idxArray
                            unsigned int _currentChunkIdx;
                            for (_currentChunkIdx = _previousChunkIdx; _currentChunkIdx < _titleCharIdx; _currentChunkIdx++) {
                                _idxArray[_currentChunkIdx] = _sectionIdx - 1;
                            }
                            _previousChunkIdx = _currentChunkIdx;
                            break;
                        }
                    }               
                }
            }

            [_numberFormatter release];

            return (NSInteger)_idxArray[_alphabeticIndex];
        }
    }
    return 0;
}

I might be naive, but I don't understand why these solutions are so baroque. I did this:

In my model, I added a method:

-(NSString *)lastInitial {
    return [self.lastname substringToIndex:1];
}

And in my tablecontroller I set the fetchedresultscontroller to use that method:

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"lastInitial" cacheName:@"Master"];

Seems to work - is there a reason that this is a bad idea? Or am I benefitting from new features in ios5 or something?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!