iPhone Contacts应用程序样式索引表视图实现
题
我的要求:我有一个直接的要求,要求在索引表视图中按字母顺序列出人的名称,索引标题是字母的起始字母(另外是顶部的搜索图标,#显示MISC值以数字和其他特殊为开始的MISC值人物)。
到目前为止,我所做的事情:1.我正在使用核心数据进行存储,并且“ last_name”被建模为“联系人实体”中的字符串属性2.我使用nsfetchedresultscontroller显示出排序的索引表视图。
完成我的要求的问题:1.首先,我无法将部分索引标题成为字母的第一个字母。戴夫(Dave)在以下文章中的建议帮助我实现了同样的事情: NsfetchedResultScontroller,由字符串的首字母创建的部分
我与戴夫(Dave)建议遇到的唯一问题是,我无法将其命名为“#”索引下的杂项。
我尝试了什么:1.我尝试将自定义比较方法添加到NSString(类别),以检查如何进行比较和部分,但是当在NSSortDescriptor Selector中指定时,该自定义方法未被调用。
这是一些代码:
@interface NSString (SortString)
-(NSComparisonResult) customCompare: (NSString*) aStirng;
@end
@implementation NSString (SortString)
-(NSComparisonResult) customCompare:(NSString *)aString
{
NSLog(@"Custom compare called to compare : %@ and %@",self,aString);
return [self caseInsensitiveCompare:aString];
}
@end
获取数据的代码:
NSArray *sortDescriptors = [NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"last_name"
ascending:YES selector:@selector(customCompare:)] autorelease]];
[fetchRequest setSortDescriptors:sortDescriptors];
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext sectionNameKeyPath:@"lastNameInitial" cacheName:@"MyCache"];
您能否让我知道我缺少什么以及如何完成要求?
解决方案
这是这个问题上非常效率的第一频道,我最终将重写。但希望这对您有帮助。
这样做的想法是“保证”在点击“标准”部分索引视图时“保证”获得真实的表部分索引。标准部分索引视图应具有用于搜索的放大镜头图标,非字母顺序的哈希标记(#)以及字母a到z的字母a至z的字母段。
不管有多少真实部分或它们的构成,都会呈现此标准观点。
最终,此代码映射部分将索引视为在获取的结果控制器中的真实存在的字母截面名称路径,或将现有的非字母(数值)部分或表格中的搜索字段中的搜索字段视为。
用户只会偶尔重新创建部分索引映射阵列(_idxArray
)在截面索引的每个触摸上,但是在每个触摸上重新创建阵列显然效率低下,并且可以调整以缓存预计算结果。
有很多地方可以开始收紧这个问题:我可以做 sectionIndexTitleLetters
例如,从一开始就静态字符串。不过,它在3GS手机上已经足够快,所以我最近还没有重新审视。
在标题中:
static NSString *sectionIndexTitleLetters = @"abcdefghijklmnopqrstuvwxyz";
在表的实现中,查看数据源:
- (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;
}
其他提示
我可能很天真,但我不明白为什么这些解决方案是如此巴洛克式。我这样做了:
在我的模型中,我添加了一种方法:
-(NSString *)lastInitial {
return [self.lastname substringToIndex:1];
}
在我的tablecontroller中,我将fetchedresultscontroller设置为使用该方法:
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"lastInitial" cacheName:@"Master"];
似乎有效 - 有原因是一个坏主意吗?还是我从iOS5中的新功能中受益?