Frage

Meine Anforderung:Ich habe diese einfache Voraussetzung für die Auflistung von Namen von Personen in alphabetischer Reihenfolge in einer indizierten Tabellenansicht, wobei Index -Titel das Ausgangsbuchstaben von Alphabeten sind (zusätzlich ein Suchymbol oben und #, um Miscal -Werte anzuzeigen, die mit einer Nummer und anderen Spezialitäten beginnen Figuren).

Was ich bisher getan habe:1. Ich verwende Kerndaten für den Speicher und "last_name" wird als Zeichenfolgeneigenschaft in der Kontakteinheit modelliert.

Probleme, die meine Anforderungen erfüllen:1. Zuerst konnte ich die Abschnittsindextitel nicht als das erste Buchstaben der Alphabete beziehen. Daves Vorschlag in der folgenden Post hat mir geholfen, dasselbe zu erreichen: NsfetchedResultsController mit Abschnitten, die durch den ersten Buchstaben einer Zeichenfolge erstellt wurden

Das einzige Problem, das ich mit Dave 'Vorschlag begegnet habe, ist, dass ich den unter "#" -Endex gruppierten Misc -Namen nicht erhalten konnte.

Was ich versucht habe:1. Ich habe versucht, eine benutzerdefinierte Vergleichsmethode mit NSString (Kategorie) hinzuzufügen, um zu überprüfen, wie der Vergleich und der Abschnitt erstellt werden. Diese benutzerdefinierte Methode wird jedoch nicht aufgerufen, wenn sie im NSSORTDESScriptor -Selektor angegeben sind.

Hier ist ein Code:

@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

Code zum Abrufen von Daten:

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

Können Sie mich wissen lassen, was mir fehlt und wie die Anforderungen erreicht werden können?

War es hilfreich?

Lösung

Dies ist ein wirklich ineffizientes Erstpass bei diesem Problem, das ich irgendwann neu schreiben werde. Aber hoffentlich wird Ihnen das helfen.

Die Idee davon besteht darin, beim Tippen auf eine "Standard" -Steilindexansicht einen realen Abschnittsindex zu "garantieren". Eine Standard-Abschnitt-Indexansicht sollte ein Lens-Symbol für die Suche, eine Hash-Marke (#) für nicht-alphabetische Abschnitte und Buchstaben a bis z für alphabetische Abschnitte haben.

Diese Standardansicht wird unabhängig davon vorgestellt, wie viele reale Abschnitte es gibt oder woraus sie bestehen.

Letztendlich kann dieser Code-Abschnitt Indizes auf realoziale alphabetische Abschnittswege im abgerufenen Ergebniscontroller oder zu realoualen nicht-alphabetischen (numerischen) Abschnitten oder zum Suchfeld im Tabellenheader nennen.

Der Benutzer erstellt nur gelegentlich das Abschnittsindex -Mapping -Array (_idxArray) Bei jeder Berührung des Abschnittsindex ist es offensichtlich ineffizient, das Array für jede Berührung wiederherzustellen und könnte optimiert werden, um vorabberechnete Ergebnisse zu cache.

Es gibt viele Orte, an denen man festhält: Ich könnte das machen sectionIndexTitleLetters Statische Saite alle Großbuchstaben von Anfang an. Es ist jedoch schnell genug auf einem 3GS -Telefon, also habe ich dies in letzter Zeit nicht erneut besucht.

Im Kopf:

static NSString *sectionIndexTitleLetters = @"abcdefghijklmnopqrstuvwxyz";

In der Implementierung der Tabellenansichtsdatenquelle:

- (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;
}

Andere Tipps

Ich mag naiv sein, aber ich verstehe nicht, warum diese Lösungen so barock sind. Ich war das:

In meinem Modell habe ich eine Methode hinzugefügt:

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

Und in meinem TableController habe ich den FetcheedResultsController so eingestellt, dass diese Methode verwendet wird:

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

Scheint zu funktionieren - gibt es einen Grund, warum dies eine schlechte Idee ist? Oder profitiere ich von neuen Funktionen in iOS5 oder so?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top