Перечисление в Objective-C Использование блока против быстрого перечисления? - PullRequest
35 голосов
/ 14 декабря 2011

Каковы преимущества и недостатки следующих двух подходов:

enumerateUsingBlock

NSArray *myArray = [[NSArray alloc] init];
[myArray enumerateObjectsUsingBlock:^(id anObject, NSUInteger idx, BOOL *stop) {
    if (anObject == someOtherObject) {
        [anObject doSomething:idx];
        *stop = YES;
    }
}];

быстрое перечисление

NSArray *myArray = [[NSArray alloc] init];
int idx = 0
for (id anObject in myArray) {
    if (anObject == someOtherObject) {
        [anObject doSomething:idx];
        break;
    }
    ++idx;
}

Ответы [ 2 ]

47 голосов
/ 14 декабря 2011

В этом блоге рассматриваются основные различия. В итоге:

  • Быстрое перечисление доступно в OS X 10.5+, блоки доступны в 10.6 +
  • Для простого перечисления быстрое перечисление немного быстрее, чем перечисление на основе блоков
  • Параллельное или обратное перечисление легче (и более эффективно) с перечислением на основе блоков, чем с быстрым перечислением
  • При перечислении по NSDictionary вы можете получить ключ и значение за одно попадание с помощью перечислителя на основе блоков, тогда как при быстром перечислении вам нужно использовать ключ для получения значения в отдельной отправке сообщения.

Что касается последней точки (перечисление NSDictionary), сравните это:

for (id key in dictionary)
{
    id obj = [dictionary objectForKey: key];
    // do something with key and obj
}

к этому:

[dictionary enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
    // do something with key and obj
}];

Кроме того, оба метода защищают изменяемые коллекции от мутаций внутри цикла перечисления. Интересно, что если вы попытаетесь изменить коллекцию внутри перечисления на основе блоков, вы получите исключение, выдаваемое CoreFoundation __NSFastEnumerationMutationHandler, предполагающее наличие некоторого общего кода под капотом.

 NSMutableArray *myArray = [NSMutableArray arrayWithObjects:@"a", @"b", nil];
 [myArray enumerateObjectsUsingBlock:^(id anObject, NSUInteger idx, BOOL *stop) {
     // Attempt to mutate the array during enumeration
     [myArray addObject:@"c"];
 }];

Выход:

2011-12-14 22:37:53.716 Untitled[5809:707] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x109614190> was mutated while being enumerated.'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff8cca7286 __exceptionPreprocess + 198
    1   libobjc.A.dylib                     0x00007fff8319ad5e objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff8cd311dc __NSFastEnumerationMutationHandler + 172
    3   CoreFoundation                      0x00007fff8cc9efb4 __NSArrayEnumerate + 612
    4   Untitled                            0x00000001094efcea main + 250
    5   Untitled                            0x00000001094efbe4 start + 52
    6   ???                                 0x0000000000000001 0x0 + 1
)
terminate called throwing an exceptionRun Command: line 1:  5809 Abort trap: 6           ./"$2"
4 голосов
/ 14 декабря 2011

Первые мысли, которые приходят мне в голову

  • Блоки доступны в iOS 4 и более поздних версиях, поэтому, если вам требуется поддержка более старых версий, вы не можете использовать синтаксис блока.

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

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

Надеюсь, это был очень грубый пример, так как фрагмент кода довольно скудный, и есть более эффективный способ сделать это;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...