Objective c “for each” (fast enumeration) — evaluation of collection?

≯℡__Kan透↙ 提交于 2019-12-22 03:55:08

问题


It seems from experimentation that the collection expression is evaluated only once. Consider this example:

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);

The output is:

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

indicating that [self fcn] is called only once.

Can anyone confirm that this is the specified (as opposed to merely observed) behavior?

What I have in mind is doing something like this:

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

instead of this:

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

Thoughts?


回答1:


This kind of for loop is called a "fast enumeration" (look at the NSFastEnumeration object). Apple's documentation says that in "for obj in expression", expression yields an object that conforms to the NSFastEnumeration protocol, so I guess that's the correct behaviour: the function is called once, an iterator is created once and used in the loop.




回答2:


In practice, collection is only evaluated once, you can check the source of clang, for example. When the documentation doesn't say things precise enough, you need to trust the implementation.

Yes I think Apple should clarify documentation. Please file a bug, Marc!

One pedantic way to get this is to read the margin of the official documentation, which can be found here. It's stated that

the enumerator has a mutation guard so that if you attempt to modify the collection during enumeration, an exception is raised. Since mutation of the object during iteration is forbidden, you can perform multiple enumerations concurrently.

so, the collection over which you iterate can't change anyway. It doesn't say whether it evaluates collection in

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

once or twice, the resulting object can't change.




回答3:


Common sense dictates it to be that way. But since it is not directly stated in the Fast Enumeration Documentation, why don't you have a look at the protocol itself:

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

This protocol is not providing methods like nextObject, or objectAtIndex, or something like that, but instead requests a C array of objects, over which is then iterated.

Although there are strong indications, no document guarantees you that the expression is only evaluated once.




回答4:


This is part of the behavior of fast enumeration. For some in-depth knowledge of the implementation of fast enumeration check out this blog post on NSBlog: Implementing Fast Enumeration.



来源:https://stackoverflow.com/questions/3882254/objective-c-for-each-fast-enumeration-evaluation-of-collection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!