11

从实验看来,集合表达式只被评估一次。考虑这个例子:

static NSArray *a;

- (NSArray *)fcn
{
    if (a == nil)
        a = [NSArray arrayWithObjects:@"one", @"two", @"three", nil];
    NSLog(@"called");
    return a;
}

...

for (NSString *s in [self fcn])
    NSLog(@"%@", s);

输出是:

2010-10-07 07:37:31.419 WidePhotoViewer Lite[23694:207] called
2010-10-07 07:37:31.420 WidePhotoViewer Lite[23694:207] one
2010-10-07 07:37:31.425 WidePhotoViewer Lite[23694:207] two
2010-10-07 07:37:31.425 WidePhotoViewer Lite[23694:207] three

表示 [self fcn] 只被调用一次。

任何人都可以确认这是指定的(而不是仅仅观察到的)行为吗?

我想到的是做这样的事情:

for (UIView *v in [innerView subviews]) {

而不是这个:

NSArray *vs = [innerView subviews];
for (UIView *v in vs) {

想法?

4

4 回答 4

13

这种 for 循环称为“快速枚举”(查看 NSFastEnumeration 对象)。苹果的文档说,在“for obj in expression”中,表达式产生一个符合 NSFastEnumeration 协议的对象,所以我猜这是正确的行为:函数被调用一次,迭代器被创建一次并在循环中使用。

于 2010-10-07T14:10:25.613 回答
7

在实践中,collection只求值一次,例如可以查看 clang 的来源。当文档说的不够准确时,您需要信任实现。

是的,我认为苹果应该澄清文档。请提交一个错误,马克!

获得此信息的一种迂腐方法是阅读官方文档的页边空白,可在此处找到。据说

枚举器有一个突变保护,因此如果您在枚举期间尝试修改集合,则会引发异常。由于禁止在迭代过程中改变对象,因此可以同时执行多个枚举。

所以,你迭代的集合无论如何都不能改变。它没有说它是否在collection评估

for(id obj in collection) { ... } 

一次或两次,生成的对象不能改变。

于 2010-10-07T16:28:52.727 回答
3

常识决定了它是这样的。但是既然在快速枚举文档中没有直接说明,为什么不看一下协议本身:

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSFastEnumeration_protocol/Reference/NSFastEnumeration.html

该协议不提供诸如 nextObject 或 objectAtIndex 之类的方法,而是请求一个 C 对象数组,然后对其进行迭代。

尽管有强烈的迹象,但没有任何文档可以保证表达式只计算一次。

于 2010-10-07T14:29:57.770 回答
0

这是快速枚举行为的一部分。有关快速枚举实现的一些深入知识,请查看 NSBlog 上的这篇博文:实现快速枚举。

于 2010-10-07T14:21:35.083 回答