这是使用快速枚举的低效方法吗? [英] Is this an inefficient way of using fast enumeration?
问题描述
我并不完全理解枚举速度有多快的细节,但比较以下两种情况:
I don't entirely understand the details of how fast enumeration works, but compare the following two cases:
for(NSObject *object in self.myParent.parentsParents.granfathersMother.cousin.unclesNephew.array) {
// do something
}
vs。
NSArray *array = self.myParent.parentsParents.granfathersMother.cousin.unclesNephew.array;
for(NSObject *object in array) {
// do something
}
在第一个例子中,它会在每次迭代时通过整个链来获取数组吗?我应该使用第二种方式吗?
In the first example, will it go through that entire chain every iteration to get the array? Should I be using the second way?
推荐答案
当Apple推出Fast Enumeration时我曾在WWDC,并且(我记得)我们是然后说右手对象被移入临时对象。此外,它必须是这样的:
I was at WWDC when Apple introduced Fast Enumeration, and (I recall) we were told then that the right hand object is moved into a temp. In addition, it must be since this works:
for([myCollection reverseObjectEnumerator]中的id foo)
for(id foo in [myCollection reverseObjectEnumerator])
您可以看到执行快速枚举的集合采用快速枚举协议(NSFastEnumeration),它有一种方法:
You can see that collections that perform fast enumeration adopt the "Fast Enumeration Protocol" (NSFastEnumeration), which has one method:
– countByEnumeratingWithState:objects:count:
该方法返回一个C数组对象,使枚举变得非常快,再次支持一次使用右侧。
That method returns a C Array of objects that lets the enumeration go very quickly, again supporting the one time use of the right side.
现在,说了这么多,目前Apple建议开发人员(在WWDC上)使用块枚举,他们声称它更快并产生更少的代码:
Now, having said all that, currently Apple advises developers (at WWDC) to use the block enumeration, which they claim is both faster and generates less code:
[myCollection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
... your code
} ];
我喜欢做的不是使用id obj,而是实际类型(避免块中的强制转换):
What I am fond of doing is not using "id obj", but the actual type (to avoid a cast in the block):
[myCollection enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop)
{
... your code
} ];
当我这样做时,编译器和分析器(4.4)都没有抱怨。
Neither the compiler nor the analyzer (4.4) complains when I do this.
如果您需要在此方法之外设置变量,则必须将其设为块变量:
If you need to set a variable outside this method, then you have to make it a block variable:
__block int foo = 0;
[myCollection enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop)
{
foo = MAX(foo, [num integerValue]);
} ];
编辑:作为澄清,你的问题的直接答案是'不',声明'自我.myParent.parentsParents.granfathersMother.cousin.unclesNephew.array'被评估一次,最终对象作为临时值存储在堆栈中。此外,您可以使用与块枚举相同的技术 - 语句被评估一次,最后返回的对象用于枚举。
as a clarification, the direct answer to your question is 'no', the statement 'self.myParent.parentsParents.granfathersMother.cousin.unclesNephew.array' is evaluated once, and the final object stored as a temp on the stack. Also, you can use the same technique with block enumeations - the statement is evaluated once and the final returned object used for the enumeration.
__block int foo = 0;
[self.myParent.parentsParents.granfathersMother.cousin.unclesNephew.array enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop)
{
foo = MAX(foo, [num integerValue]);
} ];
EDIT2:我在SO上发现了另一个讨论同一主题的线程。我忽略了关于块枚举的一点是你可以指定它们应该使用稍微复杂的方法同时(或反向)运行:
I found another thread on SO where this same topic was discussed. The one point I missed regarding block enumeration is that you can specify that they should be run concurrently (or in reverse) using the slightly more complex method:
enumerateObjectsWithOptions:usingBlock:
随着iOS设备获得越来越多的核心,这可能是取决于你正在做什么,这是一场大胜。
As iOS devices get more and more core's this could potentially be a big win depending on what you're doing.
@ bbum对这个问题的反应(以及其他人)这里。
@bbum's response to the question (and others too) are here.
这篇关于这是使用快速枚举的低效方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!