Question

Mon exigence: J'ai bien compris exigence avant d'énumérer les noms des personnes dans l'ordre alphabétique dans une Indexed vue de tableau avec des titres d'index étant la première lettre de l'alphabet (en plus une icône de recherche en haut et # pour afficher les valeurs misc qui commencent par un numéro et un autre spécial caractères).

Ce que je l'ai fait jusqu'à présent: 1. J'utilise des données de base pour le stockage et « last_name » est modelée comme une propriété de chaîne dans l'entité Contacts 2. Je me sers d'un NSFetchedResultsController pour afficher la vue triée table indexée.

Questions accomplir mon exigence: 1. Tout d'abord, je ne pouvais pas obtenir les titres d'index de section pour être la première lettre de l'alphabet. La suggestion de Dave dans le post suivant, m'a aidé à obtenir le même: NSFetchedResultsController avec sections créées par la première lettre d'une chaîne

La seule question que je rencontrais avec suggestion « Dave est que je ne pouvais pas obtenir le nom regroupés sous divers indice « # ».

Ce que j'ai essayé: 1. J'ai essayé d'ajouter une méthode comparer personnalisée pour NSString (catégorie) pour vérifier comment la comparaison et la section est faite, mais cette méthode personnalisée ne sont pas appelés lorsque cela est spécifié dans le sélecteur NSSortDescriptor.

Voici un 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 pour récupérer les données:

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

Pouvez-vous me faire savoir ce que je manque et comment l'exigence peut être accompli?

Était-ce utile?

La solution

Ceci est un premier passage vraiment inefficace à ce problème, que je vais réécrire la suite. Mais nous espérons que cela vous aidera.

L'idée de c'est de « garantir » obtenir un véritable index de la section tableau arrière lorsque vous touchez une vue d'index de la section « standard ». Une vue de l'indice de la section standard devrait avoir une icône de loupe pour la recherche, une marque dièse (#) pour les sections non alphabétiques, et les lettres A à Z pour les sections alphabétique.

Ce point de vue standard est présenté indépendamment du nombre de sections réelles, ou quant à ce qu'ils sont faits.

En fin de compte, ce code des cartes indices de vue de la section des chemins de nom de la section alphabétique réel existant dans le contrôleur tiré par les cheveux de résultats, ou aux sections non alphabétiques (numériques) réel existant, ou le champ de recherche dans l'en-tête de table.

L'utilisateur ne recréer de temps en temps le tableau de mappage d'index de section (_idxArray) sur chaque touche de l'index de la section, mais de recréer le tableau sur chaque touche est évidemment inefficace et pourrait être modifié aux résultats pré-calculés cache.

Il y a beaucoup d'endroits pour commencer à resserrer cette place: je pouvais faire la chaîne statique sectionIndexTitleLetters majuscules dès le début, par exemple. Il est assez rapide sur un téléphone 3GS, cependant, donc je ne l'ai pas revu récemment.

Dans l'en-tête:

static NSString *sectionIndexTitleLetters = @"abcdefghijklmnopqrstuvwxyz";

Dans la mise en œuvre de la vue de la table source de données:

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

Autres conseils

Je pourrais être naïf, mais je ne comprends pas pourquoi ces solutions sont si baroque. Je l'ai fait:

Dans mon modèle, j'ai ajouté une méthode:

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

Et dans mon tablecontroller je mis le fetchedresultscontroller à utiliser cette méthode:

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

Il semble au travail - est-il une raison que cela est une mauvaise idée? Ou suis-je bénéficiant de nouvelles fonctionnalités iOS5 ou quelque chose?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top