Множественное перечисление NSArray - PullRequest
5 голосов
/ 14 мая 2011

Допустим, у меня есть три массива одинакового размера. Я должен сделать что-то со всеми объектами. Если бы я использовал стандартный массив C, я бы написал что-то вроде

for (i = 0; i < size; i++) {
    doSomething(array1[i]);   // or [[array1 objectAtIndex:i] doSomething];
    doSomethingElse(array2[i]);   // or [[array2 objectAtIndex:i] doSomethingElse];
    doSomethingReallySpecial(array3[i]);   // or [[array3 objectAtIndex:i] doSomethingReallySpecial];
}

В Objective C мы получили больше способов циклически проходить по объектам в NSArray: быстрое перечисление, основанное на блоках перечисление и использование перечислителей. Какой я должен использовать и почему? Какая разница?

Редактировать
На самом деле этот вопрос можно сформулировать так: если нужно использовать индекс элемента массива, какое перечисление следует использовать?

Ответы [ 2 ]

4 голосов
/ 14 мая 2011

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

Использование блоков обеспечивает большую гибкость. Метод может принять блок в качестве аргумента и использовать его для перечисления нескольких различных коллекций:

- (void) doSomethingToFruits:(void(^)(id,NSUInteger,BOOL*))block
{
    [apples enumerateObjectsUsingBlock:block];
    [bananas enumerateObjectsUsingBlock:block];
    [kiwis enumerateObjectsUsingBlock:block];
}

Вы также можете использовать аргумент параметров в enumerateObjectsUsingBlock:options: для одновременного перечисления содержимого.

Что мне нравится в быстром перечислении, так это то, что протокол NSFastEnumeration позволяет мне добавлять метод, который принимает либо массивы или наборы (или хеш-таблицы, либо что-то еще), но все еще имеет проверку статического типа в аргументе:

- (void) addObjectsFromCollection:(id<NSFastEnumeration>)coll
{
    for (id obj in coll) [self addObject:obj];
}

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

Добавление:

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

0 голосов
/ 14 мая 2011

Вы должны использовать тот, который наиболее четко выражает намерение вашего кода для читателей кода.Если вы не определили эти циклы как существенное узкое место в производительности, способность поддерживать ваш код будет гораздо более важной.Если вы не хотите использовать цикл в стиле C, -[NSArray enumerateObjectsUsingBlock:] предоставляет и текущий элемент, и индекс, и может использоваться для архивирования нескольких массивов.Я подозреваю, что для нескольких массивов подход в стиле C часто будет эффективно эквивалентен по производительности - и, возможно, понятнее читателю, но вы должны профилировать его, чтобы быть уверенным.

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

...