pour chaque boucle dans Objective-C pour accéder au dictionnaire NSMutable

268

Je rencontre des difficultés pour accéder aux clés et valeurs de dictionnaire mutables dans Objective-C.

Supposons que j'ai ceci:

NSMutableDictionary *xyz=[[NSMutableDictionary alloc] init];

Je peux définir des clés et des valeurs. Maintenant, je veux juste accéder à chaque clé et valeur, mais je ne connais pas le nombre de clés définies.

En PHP, c'est très facile, quelque chose comme suit:

foreach ($xyz as $key => $value)

Comment est-ce possible dans Objective-C?

Sagar R. Kothari
la source

Réponses:

662
for (NSString* key in xyz) {
    id value = xyz[key];
    // do stuff
}

Cela fonctionne pour chaque classe conforme au protocole NSFastEnumeration (disponible sur 10.5+ et iOS), bien qu'il s'agisse de l' NSDictionaryune des rares collections qui vous permet d'énumérer les clés au lieu des valeurs. Je vous suggère de lire sur l' énumération rapide dans la rubrique Programmation des collections .

Oh, je dois ajouter cependant que vous ne devez JAMAIS modifier une collection pendant son énumération.

zneak
la source
4
Je me demandais, ça n'aurait pas dû être le cas: pour (clé NSString * dans [xyz allKeys]) ?? Ou cela n'a-t-il pas vraiment d'importance.
FlowUI. SimpleUITesting.com
6
@ user76859403 L'énumération d'un dictionnaire, en fait, énumère les clés. for (NSString* key in [xyz allKeys])est conceptuellement la même chose.
zneak
Utilisez [xyz allKeys] si vous devez muter le dictionnaire lors de l'énumération des clés. Voir ma réponse ci-dessous.
Brody Robertson
Cette boucle renvoie-t-elle toujours le même ordre? Ou avons-nous besoin d'une autre façon de l'utiliser pour les sections TableView?
ymutlu
1
@ymutlu, les dictionnaires Cocoa ne sont pas classés. Cela signifie que l'ordre dans lequel ils itèrent peut changer chaque fois que vous les modifiez.
zneak
98

Juste pour ne pas omettre l'option 10.6+ pour énumérer les clés et les valeurs à l'aide de blocs ...

[dict enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
    NSLog(@"%@ = %@", key, object);
}];

Si vous souhaitez que les actions se produisent simultanément:

[dict enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent
                              usingBlock:^(id key, id object, BOOL *stop) {
    NSLog(@"%@ = %@", key, object);
}];
Quinn Taylor
la source
2
3 façons différentes d'énumérer à travers un dictionnaire. . . heh, cela me rappelle la réponse "Strangest Language Feature" où VB a 7 différents types de boucles.
dreamlax
3
Eh bien ... objectEnumerator a été ajouté en 1994, le for (... dans ...) vers 2006 et les blocs ont été ajoutés en 2009. La forme de bloc d'énumération est une conséquence naturelle.
bbum
Cela semble être plus rapide que la norme pour ... dans la construction: oneofthesedaysblog.com/block-vs-for-in-objective-c-enumeration
lkraider
1
@lkraider, j'ai commenté ce post, qui compare en fait l'énumération basée sur les blocs avec une ancienne boucle for, pas la for ... in construct.
Quinn Taylor
À quoi ça sert *stop? Comment l'utilisez-vous? Une référence?
borisdiakur
13

Si vous devez muter le dictionnaire lors de l'énumération:

for (NSString* key in xyz.allKeys) {
    [xyz setValue:[NSNumber numberWithBool:YES] forKey:key];
}
Brody Robertson
la source
La raison en est de allKeysretour une copie des clés. Il est donc sûr de muter le dictionnaire.
Honghao Zhang
5

La façon la plus simple d'énumérer un dictionnaire est

for (NSString *key in tDictionary.keyEnumerator) 
{
    //do something here;
}

tDictionaryest le NSDictionaryou NSMutableDictionaryvous voulez répéter.

Avinash
la source
2

Une énumération rapide a été ajoutée dans la version 10.5 et dans l'iPhone OS, et c'est beaucoup plus rapide, pas seulement le sucre syntaxique. Si vous devez cibler l'ancien runtime (c'est-à-dire 10.4 et versions antérieures), vous devrez utiliser l'ancienne méthode d'énumération:

NSDictionary *myDict = ... some keys and values ...
NSEnumerator *keyEnum = [myDict keyEnumerator];
id key;

while ((key = [keyEnum nextObject]))
{
    id value = [myDict objectForKey:key];
    ... do work with "value" ...
}

Vous ne libérez pas l'objet énumérateur et vous ne pouvez pas le réinitialiser. Si vous voulez recommencer, vous devez demander un nouvel objet énumérateur dans le dictionnaire.

dreamlax
la source
1

Vous pouvez utiliser -[NSDictionary allKeys]pour accéder à toutes les clés et les parcourir.

gcamp
la source
2
Certes, mais cela crée un tableau supplémentaire auto-libéré, ce qui peut être assez inutile, en particulier pour les dictionnaires avec beaucoup de clés.
Quinn Taylor