Objective-C enumerateUsingBlock vs fast enumeration?

时间:2011-12-14 18:21:23

标签: objective-c

以下两种方法的优点和缺点是什么:

enumerateUsingBlock

NSArray *myArray = [[NSArray alloc] init];
[myArray enumerateObjectsUsingBlock:^(id anObject, NSUInteger idx, BOOL *stop) {
    if (anObject == someOtherObject) {
        [anObject doSomething:idx];
        *stop = YES;
    }
}];

快速枚举

NSArray *myArray = [[NSArray alloc] init];
int idx = 0
for (id anObject in myArray) {
    if (anObject == someOtherObject) {
        [anObject doSomething:idx];
        break;
    }
    ++idx;
}

2 个答案:

答案 0 :(得分:47)

This blog post涵盖了主要差异。总结:

  • OS X 10.5+提供快速枚举,10.6 +
  • 提供块
  • 对于简单枚举,快速枚举比基于块的枚举快一点
  • 使用基于块的枚举进行并发或反向枚举比使用快速枚举更容易(且性能更高)
  • 枚举NSDictionary时,您可以使用基于块的枚举器获得键和值,而使用快速枚举时,您必须使用该键在单独的消息发送中检索值。

关于最后一点(NSDictionary枚举),比较一下:

for (id key in dictionary)
{
    id obj = [dictionary objectForKey: key];
    // do something with key and obj
}

到此:

[dictionary enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
    // do something with key and obj
}];

此外,这两种方法都保护可变集合免受枚举循环内的变异的影响。有趣的是,如果你试图在基于块的枚举中改变集合,你会得到CoreFoundation的__NSFastEnumerationMutationHandler抛出的异常,这表明在底层有一些常用代码。

 NSMutableArray *myArray = [NSMutableArray arrayWithObjects:@"a", @"b", nil];
 [myArray enumerateObjectsUsingBlock:^(id anObject, NSUInteger idx, BOOL *stop) {
     // Attempt to mutate the array during enumeration
     [myArray addObject:@"c"];
 }];

输出:

2011-12-14 22:37:53.716 Untitled[5809:707] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x109614190> was mutated while being enumerated.'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff8cca7286 __exceptionPreprocess + 198
    1   libobjc.A.dylib                     0x00007fff8319ad5e objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff8cd311dc __NSFastEnumerationMutationHandler + 172
    3   CoreFoundation                      0x00007fff8cc9efb4 __NSArrayEnumerate + 612
    4   Untitled                            0x00000001094efcea main + 250
    5   Untitled                            0x00000001094efbe4 start + 52
    6   ???                                 0x0000000000000001 0x0 + 1
)
terminate called throwing an exceptionRun Command: line 1:  5809 Abort trap: 6           ./"$2"

答案 1 :(得分:4)

我想到的第一个想法

  • iOS 4及更高版本中提供了块,因此如果您需要支持旧版本,则无法使用块语法。

  • 除了你所做的事情之外,它们非常相同,你不会在街区版本中意外搞砸柜台。

  • 另一个潜在的区别是你可以在其他地方定义块,并根据你的状态传入不同的块。

希望这只是一个非常粗略的例子,因为代码片段非常差并且有更有效的方法来执行此操作;)

相关问题