Быстрое перечисление против NSEnumerator в Objective-C
Я видел это снова и снова, почему именно быстрее использовать быстрое перечисление в циклах, а не NSEnumerator
с помощью nextObject:
,
3 ответа
NSEnumerator
это старый способ перечислять коллекции. Он включает создание объекта для представления перечисления, а затем вызов метода для каждой отдельной итерации. Несмотря на то, что в течение многих лет это было совершенно исправно, оно не очень эффективно, так как включает в себя, по крайней мере, одну отправку сообщения на каждую итерацию цикла. NSFastEnumeration
это более современный подход, который использует поддержку родного языка для обеспечения гораздо более эффективного перечисления. Он работает под капотом, создает структуру, которая представляет текущее состояние перечисления, и многократно вызывает -countByEnumeratingWithState:objects:count:
на коллекции. Этот метод возвращает массив объектов C в objects
Out-Param, а также счетчик в 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.
GNUstep libs / base / trunk / Source / NSEnumerator.m countByEnumeratingWithState: objects: count:
Это не то же самое, что реализация 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;
}
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. Я забыл, как массив выглядит в консоли.