Подтвердить что ты не робот

Fast Enumeration Vs NSEnumerator в Objective-C

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

4b9b3361

Ответ 1

NSEnumerator - это старый способ перечислить коллекции. Он включает в себя создание объекта для представления перечисления, а затем вызов метода для него для каждой отдельной итерации. Хотя это было прекрасно исправным на протяжении многих лет, оно не очень эффективно, поскольку оно включает по крайней мере одно сообщение, отправляемое на каждую итерацию цикла. NSFastEnumeration - это более современный подход, который использует поддержку родного языка для обеспечения гораздо более эффективного перечисления. Способ, которым он работает под капотом, заключается в создании структуры, которая представляет текущее состояние перечисления и многократно вызывает -countByEnumeratingWithState:objects:count: в коллекции. Этот метод возвращает массив массивов C в objects out-param, а также счетчик в параметре count out-param. Это позволяет вызывающему затем перебирать массив 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

Это не то же самое, что 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;
}

Ответ 3

NSArray *array = something;

array = {{1,2}, {2,3}, {3,4}}

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

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

или быстрое перечисление работает следующим образом

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

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