para cada loop no Objective-C para acessar o dicionário NSMutable

268

Estou encontrando alguma dificuldade em acessar valores e chaves de dicionário mutáveis ​​no Objective-C.

Suponha que eu tenho isso:

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

Eu posso definir chaves e valores. Agora, eu só quero acessar cada chave e valor, mas não sei o número de chaves definidas.

No PHP, é muito fácil, da seguinte maneira:

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

Como é possível no Objective-C?

Sagar R. Kothari
fonte

Respostas:

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

Isso funciona para todas as classes que estão em conformidade com o protocolo NSFastEnumeration (disponível em 10.5+ e iOS), embora NSDictionaryseja uma das poucas coleções que permite enumerar chaves em vez de valores. Sugiro que você leia sobre enumeração rápida no tópico de programação de coleções .

Devo acrescentar, no entanto, que você NUNCA deve modificar uma coleção enquanto enumera através dela.

zneak
fonte
4
Eu queria saber, não deveria ter sido: para (chave NSString * em [xyz allKeys]) ?? Ou isso realmente não importa.
FlowUI. SimpleUITesting.com
6
@ user76859403 Na verdade, enumerar um dicionário enumera as chaves. for (NSString* key in [xyz allKeys])conceitualmente é a mesma coisa.
zneak
Use [xyz allKeys] se precisar alterar o dicionário enquanto enumera as chaves. Veja minha resposta abaixo.
Brody Robertson
Esse loop retorna a mesma ordem o tempo todo? Ou precisamos de outra maneira de usá-lo nas seções TableView?
Ymutlu
1
@ymutlu, os dicionários de cacau são desordenados. Isso significa que a ordem na qual eles iteram pode mudar sempre que você os modifica.
Zneak 31/10/14
98

Apenas para não deixar de fora a opção 10.6+ para enumerar chaves e valores usando blocos ...

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

Se você deseja que as ações ocorram simultaneamente:

[dict enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent
                              usingBlock:^(id key, id object, BOOL *stop) {
    NSLog(@"%@ = %@", key, object);
}];
Quinn Taylor
fonte
2
3 maneiras diferentes de enumerar através de um dicionário. . . heh, isso me lembra a resposta "Strangest Language Feature", onde o VB tem 7 tipos diferentes de loops.
dreamlax
3
Bem ... objectEnumerator foi adicionado em 1994, o for (... in ...) em cerca de 2006 e Blocos foram adicionados em 2009. A forma de enumeração em bloco é precipitação natural.
bbum
Este parece ser mais rápido do que o padrão para ... em construção: oneofthesedaysblog.com/block-vs-for-in-objective-c-enumeration
lkraider
1
@lkraider, comentei nesse post, que na verdade compara a enumeração baseada em bloco com um loop for antigo, não o for ... na construção.
Quinn Taylor
Para que serve *stop? Como você faz uso disso? Alguma referência?
precisa saber é o seguinte
13

Se você precisar alterar o dicionário enquanto enumera:

for (NSString* key in xyz.allKeys) {
    [xyz setValue:[NSNumber numberWithBool:YES] forKey:key];
}
Brody Robertson
fonte
O motivo é allKeysretornar uma cópia das chaves. Portanto, é seguro alterar o dicionário.
Honghao Zhang
5

A maneira mais fácil de enumerar um dicionário é

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

onde tDictionaryestá o NSDictionaryou NSMutableDictionaryvocê deseja iterar.

Avinash
fonte
2

A enumeração rápida foi adicionada na versão 10.5 e no iPhone OS, e é significativamente mais rápida, não apenas o açúcar sintático. Se você precisar direcionar o tempo de execução mais antigo (por exemplo, 10.4 e versões anteriores), precisará usar o método antigo de enumerar:

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" ...
}

Você não libera o objeto enumerador e não pode redefini-lo. Se você deseja recomeçar, solicite um novo objeto de enumerador no dicionário.

dreamlax
fonte
1

Você pode usar -[NSDictionary allKeys]para acessar todas as chaves e fazer um loop através delas.

gcamp
fonte
2
É verdade, mas isso cria uma matriz extra liberada automaticamente, o que pode ser um grande desperdício, especialmente para dicionários com muitas chaves.
Quinn Taylor