【发布时间】:2023-03-03 12:02:02
【问题描述】:
我一遍又一遍地看到这一点,为什么在循环中使用快速枚举比使用 nextObject: 的 NSEnumerator 更快。
【问题讨论】:
标签: objective-c fast-enumeration nsenumerator
我一遍又一遍地看到这一点,为什么在循环中使用快速枚举比使用 nextObject: 的 NSEnumerator 更快。
【问题讨论】:
标签: objective-c fast-enumeration nsenumerator
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 数组的迭代。
【讨论】:
enumerateObjectsUsingBlock: 将与快速枚举一样快(NSArray)或明显更快(枚举值时为 NSDictionary)......
GNUstep libs/base/trunk/Source/NSEnumerator.mcountByEnumeratingWithState: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;
数组 = { {1,2}, {2,3}, {3,4} }
这意味着数组是数组的数组。那么如何访问所有数组及其值。 我们可以像这样使用for循环
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。我忘记了数组在控制台中的样子。
【讨论】: