【问题标题】:Objective-C enumerateObjectsUsingBlock vs fast enumeration?Objective-C enumerateObjectsUsingBlock 与快速枚举?
【发布时间】:2011-12-14 18:21:22
【问题描述】:

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

enumerate using block

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

fast enumeration

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

【问题讨论】:

标签: objective-c


【解决方案1】:

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"

【讨论】:

  • 抛开性能不谈,你们第一眼觉得哪个版本更容易阅读?
  • @rsanchezsaez 有趣的问题!我发现字典键上的for 循环更具可读性。块语法对我来说仍然不直观。
  • 对于键值,我发现block更直观(我来自C(++)并且只使用过一次block)
  • 可能是因为我偶尔用python吧。
  • 我并不是说这是错误的,但这篇文章表明基于块的效果更好。 stackoverflow.com/a/4487012/296446
【解决方案2】:

我想到的第一个想法

  • 块在 iOS 4 及更高版本中可用,因此如果您需要支持旧版本,则不能使用块语法。

  • 就它们所做的事情而言,它们几乎是相当的,除了你不会在块版本中意外弄乱计数器。

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

希望这只是一个非常粗略的示例,因为代码 sn-p 很差,并且有更有效的方法来做到这一点;)

【讨论】:

  • 另外,如果我没记错的话,在 WWDC 2010 视频中指出,块枚举比快速枚举的性能还要好。
  • 这就是视频的问题,你知道里面有好东西,但祝你以后能再次找到它。我查看了Enumeration: Traversing a Collection’s Elements 的文档,并没有特别提到性能提升:S
  • 其实我刚找到。这是 2010 年的“iOS 4 Foundation 中的新增功能”视频。
  • 干得好,即使你知道它在什么视频中,也很难找到它。
猜你喜欢
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
  • 2012-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-22
相关资源
最近更新 更多