iPhone app contatti stile implementazione vista tabella indicizzata
Domanda
la mia richiesta: Ho questo requisito dritto in avanti di elencare i nomi delle persone in ordine alfabetico in una visualizzazione tabella indicizzata con i titoli di indice sta per la lettera iniziale di alfabeti (in aggiunta un icona di ricerca in alto e # ai valori Misc di visualizzazione, che inizia con un numero e altri speciali caratteri).
Che cosa ho fatto finora: 1. Sto usando i dati di base per il deposito e "cognome" è modellato come una proprietà stringa nel soggetto Contatti 2.I sto usando un NSFetchedResultsController per visualizzare la allineati indicizzata vista tabella.
Problemi di realizzare la mia richiesta: 1. Prima di tutto, non ho potuto ottenere i titoli di indice sezione per essere la prima lettera di alfabeti. il suggerimento di Dave nel seguente post, mi ha aiutato a ottenere lo stesso: NSFetchedResultsController con sezioni creato da prima lettera di una stringa
L'unico problema che ho incontrato con il suggerimento Dave' è che non ho potuto ottenere il nome misc raggruppate sotto l'indice '#'.
Quello che ho cercato: 1. Ho provato ad aggiungere un metodo personalizzato per confrontare NSString (categoria) per verificare come il confronto e la sezione è fatta ma che metodo personalizzato non vengono chiamati quando specificato nel selettore NSSortDescriptor.
Ecco il codice:
@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
Codice per recuperare i dati:
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"];
Puoi farmi sapere che cosa mi manca e come il requisito può essere realizzato?
Soluzione
Questo è un passaggio di prima davvero inefficiente a questo problema, che ho intenzione di riscrivere alla fine. Ma spero che questo vi aiuterà.
L'idea di questo è quello di "garanzia" ottenere una vera e propria tabella indice sezione posteriore quando si tocca una vista indice sezione "standard". Una vista indice sezione standard dovrebbe avere un icona lente per la ricerca, un cancelletto (#) per le sezioni non alfabetici, e le lettere da A a Z per le sezioni alfabetiche.
Questa visualizzazione standard viene presentata indipendentemente dal numero di sezioni reale ci sono, o che cosa sono fatti di.
In definitiva, questo codice visualizza mappe indici di sezione per reale esistente percorsi di nome sezione alfabetici nel controllore risultati caricata o sezioni reali-esistente non alfabetici (numerici), o per il campo di ricerca nell'intestazione della tabella.
L'utente avrà solo occasionalmente ricreare l'array mappatura indice di sezione (_idxArray
) su ogni tocco dell'indice sezione, ma ricreare la matrice su ciascun contatto è ovviamente inefficiente e potrebbe essere ottimizzato per la cache risultati precalcolati.
Ci sono un sacco di posti per iniziare inasprimento questo in su: avrei potuto fare la stringa sectionIndexTitleLetters
statica tutto maiuscolo fin dall'inizio, per esempio. E 'abbastanza veloce su un telefono 3GS, però, così non ho rivisitato questo di recente.
Nel intestazione:
static NSString *sectionIndexTitleLetters = @"abcdefghijklmnopqrstuvwxyz";
Nell'attuazione della sorgente vista tabella dati:
- (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;
}
Altri suggerimenti
Potrei essere ingenuo, ma non capisco il motivo per cui queste soluzioni sono così barocca. Ho fatto questo:
Nel mio modello, ho aggiunto un metodo:
-(NSString *)lastInitial {
return [self.lastname substringToIndex:1];
}
E nella mia tablecontroller ho impostato la fetchedresultscontroller di utilizzare quel metodo:
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"lastInitial" cacheName:@"Master"];
sembra funzionare - c'è un motivo che si tratta di una cattiva idea? O sto beneficiando di nuove funzionalità di iOS5 o qualcosa del genere?