для каждого цикла в Objective-C для доступа к словарю NSMutable

268

Я нахожу некоторые трудности в доступе к изменяемым словарным ключам и значениям в Objective-C.

Предположим, у меня есть это:

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

Я могу установить ключи и значения. Теперь я просто хочу получить доступ к каждому ключу и значению, но я не знаю количество установленных ключей.

В PHP это очень просто, примерно так:

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

Как это возможно в Objective-C?

Сагар Р. Котари
источник

Ответы:

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

Это работает для каждого класса, который соответствует протоколу NSFastEnumeration (доступен в 10.5+ и iOS), хотя NSDictionaryявляется одной из немногих коллекций, которая позволяет перечислять ключи вместо значений. Я предлагаю вам прочитать о быстром перечислении в теме программирования коллекций .

О, я должен добавить, однако, что вы НИКОГДА не должны изменять коллекцию при ее перечислении.

zneak
источник
4
Мне было интересно, не так ли: for (ключ NSString * в [xyz allKeys]) ?? Или это действительно не имеет значения.
FlowUI. SimpleUITesting.com
6
@ user76859403 Перечисление словаря, фактически, перечисляет ключи. for (NSString* key in [xyz allKeys])концептуально то же самое.
zneak
Используйте [xyz allKeys], если вам нужно изменить словарь при перечислении ключей. Смотрите мой ответ ниже.
Броуди Робертсон
Этот цикл все время возвращает один и тот же порядок? Или нам нужен другой способ использовать его для разделов TableView?
ymutlu
1
@ymutlu, словари какао не упорядочены. Это означает, что порядок, в котором они повторяются, может изменяться при каждом их изменении.
zneak
98

Только чтобы не пропустить опцию 10.6+ для перечисления ключей и значений с использованием блоков ...

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

Если вы хотите, чтобы действия происходили одновременно:

[dict enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent
                              usingBlock:^(id key, id object, BOOL *stop) {
    NSLog(@"%@ = %@", key, object);
}];
Куинн Тейлор
источник
2
3 разных способа перечисления через словарь. , , хех, это напоминает мне ответ "Strangest Language Feature", где VB имеет 7 различных типов циклов.
Dreamlax
3
Что ж ... objectEnumerator был добавлен в 1994 году, for (... in ...) примерно в 2006 году, а блоки были добавлены в 2009 году. Блочная форма перечисления - это естественные последствия.
bbum
Кажется, это быстрее, чем стандарт для ... в конструкции: oneofthesedaysblog.com/block-vs-for-in-objective-c-enumeration
lkraider
1
@lkraider, я прокомментировал этот пост, который фактически сравнивает основанное на блоках перечисление со старым циклом for, а не for ... в конструкции.
Куинн Тейлор
Для чего *stop? Как вы используете это? Любая ссылка?
Борисдиакур
13

Если вам нужно изменить словарь при перечислении:

for (NSString* key in xyz.allKeys) {
    [xyz setValue:[NSNumber numberWithBool:YES] forKey:key];
}
Броди Робертсон
источник
Причина в том, что allKeysвозвращает копию ключей. Так что безопасно мутировать словарь.
Хунхао Чжан
5

Самый простой способ перечислить словарь

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

где tDictionaryнаходится NSDictionaryили NSMutableDictionaryвы хотите повторить.

Авинаш
источник
5

Я предлагаю вам прочитать перечисление: пересекающее на элементы коллекции часть коллекций Руководства по программированию на какао . Существует пример кода для ваших нужд.

Лоран Etiemble
источник
Это хорошие ссылки, хотя размещенный код @zneak гораздо проще и быстрее, если вы можете собрать для 10.5+ или iPhone.
Куинн Тейлор
2

Быстрое перечисление было добавлено в 10.5 и в iPhone OS, и это значительно быстрее, а не только синтаксический сахар. Если вам нужно ориентироваться на более раннюю среду выполнения (то есть 10.4 и обратно), вам придется использовать старый метод перечисления:

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

Вы не освобождаете объект перечислителя и не можете его сбросить. Если вы хотите начать все сначала, вы должны запросить новый объект перечислителя из словаря.

dreamlax
источник
1

Вы можете использовать, -[NSDictionary allKeys]чтобы получить доступ ко всем ключам и пройти через него.

gcamp
источник
2
Да, но это создает дополнительный автоматически выпущенный массив, который может быть довольно расточительным, особенно для словарей с большим количеством ключей.
Куинн Тейлор