我正在寻找在NSArray上进行迭代的标准用法。我的代码必须适合OS X 10.4+。

最佳答案

10.5 +/iOS的一般首选代码。

for (id object in array) {
    // do something with object
}

此构造用于枚举符合 NSFastEnumeration 协议(protocol)的集合中的对象。这种方法具有速度优势,因为它在一个缓冲区中存储了指向多个对象(通过单个方法调用获得)的指针,并使用指针算法通过在缓冲区中前进来遍历它们。这比每次通过循环调用-objectAtIndex:都要快得多。

还值得注意的是,尽管从技术上讲,您可以使用for-in循环逐步浏览NSEnumerator,但我发现这实际上使快速枚举的所有速度优势无效。原因是NSEnumerator的默认-countByEnumeratingWithState:objects:count:实现每次调用仅在缓冲区中放置一个对象。

我在radar://6296108中报告了此问题(NSEnumerators的快速枚举速度很慢),但返回结果为“不固定”。原因是快速枚举会预取一组对象,并且如果您只想枚举枚举器中的给定点(例如直到找到特定的对象或满足条件),并在中断后使用相同的枚举器在循环中,通常会跳过多个对象。

如果要为OS X 10.6/iOS 4.0及更高版本进行编码,则还可以选择使用基于块的API枚举数组和其他集合:
[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
    // do something with object
}];

您还可以使用-enumerateObjectsWithOptions:usingBlock:并传递NSEnumerationConcurrent和/或NSEnumerationReverse作为options参数。

10.4或更早版本

10.5之前版本的标准习惯用法是使用NSEnumerator和while循环,如下所示:
NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
  // do something with object
}

我建议保持简单。将自己绑定(bind)到数组类型是不灵活的,无论如何,使用-objectAtIndex:声称的速度提高与在10.5+上进行快速枚举的改进无关紧要。 (快速枚举实际上是在基础数据结构上使用指针算术,并消除了大多数方法调用开销。)过早的优化从来都不是一个好主意-它导致困惑的代码来解决反正不是您的瓶颈的问题。

当使用-objectEnumerator时,您可以轻松地切换到另一个可枚举的集合(例如NSSetNSDictionary中的键等),甚至切换到-reverseObjectEnumerator 来向后枚举数组,而无需更改其他代码。如果迭代代码在某个方法中,则您甚至可以传入任何NSEnumerator,而该代码甚至不必在乎它的迭代方式。此外,只要有更多对象,NSEnumerator(至少由Apple Code提供)将保留其枚举的集合,因此您不必担心自动释放的对象将存在多长时间。
NSEnumerator(或快速枚举)可以保护您免受的最大伤害是在枚举时在您不知情的情况下对您下面的可变集合(数组或其他形式)进行了更改。如果按索引访问对象,则可能会遇到奇怪的异常或异常错误(通常是在问题发生后很长时间),这很容易调试。使用标准习语之一进行枚举具有“快速失败”的行为,因此,当您在发生突变后尝试访问下一个对象时,该问题(由错误的代码引起)将立即显现出来。随着程序变得更加复杂和多线程,或者甚至依赖于第三方代码可能会修改的内容,脆弱的枚举代码变得越来越有问题。封装和抽象FTW! :-)

关于objective-c - 如何遍历NSArray?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/992901/

10-11 00:32