0

私の要件: インデックス タイトルがアルファベットの開始文字であるインデックス付きテーブル ビューに、人の名前をアルファベット順にリストするという単純な要件があります (さらに、上部に検索アイコンと、数字で始まるその他の値を表示するための # があります)。およびその他の特殊文字)。

これまでに行ったこと: 1. ストレージにコア データを使用しており、「last_name」は連絡先エンティティの文字列プロパティとしてモデル化されています 2. NSFetchedResultsController を使用して、並べ替えられたインデックス付きテーブル ビューを表示しています。

要件を達成するための問題: 1. まず、セクション インデックスのタイトルをアルファベットの最初の文字にすることができませんでした。次の投稿でのデイブの提案は、同じことを達成するのに役立ちました:文字列の最初の文字によって作成されたセクションを持つ NSFetchedResultsController

Dave の提案で遭遇した唯一の問題は、"#" インデックスの下にグループ化されたその他の名前を取得できなかったことです。

私が試したこと: 1.カスタム比較メソッドを NSString (カテゴリ) に追加して、比較とセクションがどのように行われるかを確認しようとしましたが、NSSortDescriptor セレクターで指定されたときにそのカスタムメソッドが呼び出されません。

ここにいくつかのコードがあります:

@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"];

不足しているものと、要件をどのように達成できるか教えていただけますか?

4

2 に答える 2

4

これは、この問題の非常に非効率的な最初のパスであり、最終的に書き直す予定です。しかし、うまくいけば、これはあなたを助けるでしょう.

これの考え方は、「標準」セクション インデックス ビューをタップしたときに実際のテーブル セクション インデックスを取得することを「保証」することです。標準のセクション インデックス ビューには、検索用の拡大レンズ アイコン、アルファベット以外のセクション用のハッシュ マーク (#)、およびアルファベット順のセクション用の文字 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;
}
于 2010-06-04T07:57:19.763 に答える
1

私は素朴かもしれませんが、なぜこれらのソリューションがそれほどバロックなのか理解できません。これは私がしました:

私のモデルでは、メソッドを追加しました:

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

そして、テーブルコントローラーで、そのメソッドを使用するように fetchedresultscontroller を設定しました。

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

うまくいくようです - これが悪い考えである理由はありますか? それとも、ios5 などの新機能の恩恵を受けているのでしょうか?

于 2012-04-28T21:30:50.690 に答える