我一遍又一遍地看到这一点,为什么在循环中使用快速枚举更快,而不是使用NSEnumerator
nextObject:
。
答案 0 :(得分:29)
NSEnumerator
是枚举集合的旧方法。它涉及创建一个表示枚举的对象,然后为每次迭代调用一个方法。虽然这可以使用多年,但它并不是非常有效,因为它涉及至少一个消息发送循环的每次迭代。 NSFastEnumeration
是更现代的方法,它利用本地语言支持来提供更有效的枚举。它的工作方式是创建一个表示当前枚举状态的结构,并在集合上重复调用-countByEnumeratingWithState:objects:count:
。此方法返回objects
out-param中的C对象数组以及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数组上的迭代。
答案 1 :(得分:2)
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;
}
答案 2 :(得分:0)
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。我忘了数组在控制台中的样子了。