Быстрое перечисление против NSEnumerator в Objective-C - PullRequest
10 голосов
/ 02 марта 2011

Я видел это снова и снова, почему именно быстрее использовать быстрое перечисление в циклах, а не NSEnumerator с использованием nextObject:.

Ответы [ 3 ]

29 голосов
/ 02 марта 2011

NSEnumerator - это старый способ перечисления по коллекциям.Он включает создание объекта для представления перечисления, а затем вызов метода для каждой отдельной итерации.Несмотря на то, что это было совершенно исправно в течение многих лет, оно не очень эффективно, так как включает в себя по крайней мере одну отправку сообщения для каждой итерации цикла.NSFastEnumeration - более современный подход, который использует поддержку родного языка для обеспечения гораздо более эффективного перечисления.Он работает под капотом, создавая структуру, которая представляет текущее состояние перечисления, и неоднократно вызывает -countByEnumeratingWithState:objects:count: в коллекции.Этот метод возвращает массив объектов C в выходном параметре objects, а также счетчик в выходном параметре count.Это позволяет вызывающей стороне затем перебирать массив C.По сути, это означает, что один вызов сообщения на кусок объектов, который, в зависимости от коллекции, может быть столь же эффективным, как один вызов сообщения для получения всех объектов.

Если у вас есть немного кода, который выглядит как

for (id obj in myArray) {
    [obj doSomething];
}

Это преобразуется компилятором в нечто, примерно эквивалентное

NSFastEnumerationState __enumState = {0};
id __objects[MAX_STACKBUFF_SIZE];
NSUInteger __count;
while ((__count = [myArray countByEnumeratingWithState:&__enumState objects:__objects count:MAX_STACKBUFF_SIZE]) > 0) {
    for (NSUInteger i = 0; i < __count; i++) {
        id obj = __objects[i];
        [obj doSomething];
    }
}

Фактические используемые переменные скрыты, и максимальный размер буфера объекта также зависит от реализации,но основная идея есть.Он переводит итерацию по коллекции obj-c в итерацию по массиву C.

2 голосов
/ 02 марта 2011

Это не то же самое, что реализация Apple, но полезно понять.

- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state  
                   objects: (id*)stackbuf
                     count: (NSUInteger)len
{
  IMP nextObject = [self methodForSelector: @selector(nextObject)];
  int i;

  state->itemsPtr = stackbuf;
  state->mutationsPtr = (unsigned long*)self;
  for (i = 0; i < len; i++)
    {
      id next = nextObject(self, @selector(nextObject));

      if (nil == next)
    {
      return i;
    }
      *(stackbuf+i) = next;
    }
  return len;
}
0 голосов
/ 02 марта 2011
NSArray *array = something;

массив = {{1,2}, {2,3}, {3,4}}

, что означает, что массив является массивом массива. так как вы можете получить доступ ко всем массивам и их значениям. мы можем использовать для цикла, как это

for (int i = 0; i < array.count; i++)
{
    NSArray x = [array objectAtIndex:i];
}

или быстрый enum работает следующим образом

for(NSArray array2 in array)
{
   // do what ever you want with this new array2.
}

это пример примера.
PS. Я забыл, как выглядит массив в консоли.

...