我一再看到这个问题,为什么在循环中使用快速枚举比使用NSEnumerator
的nextObject:
更快呢。
我一再看到这个问题,为什么在循环中使用快速枚举比使用NSEnumerator
的nextObject:
更快呢。
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 数组的迭代。
GNUstep libs/base/trunk/Source/NSEnumerator.m countByEnumeratingWithState:objects:count:
虽然与苹果的实现不同,但这对理解很有帮助。
- (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;
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. 我忘记了控制台中数组的样子。
enumerateObjectsUsingBlock:
在枚举NSArray时速度非常快,而在枚举NSDictionary的值时速度更快。 - bbum