我正在寻找一个标准的习语来迭代NSArray.我的代码需要适合OS X 10.4+.

推荐答案

10.5+/iOS的首选代码.

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

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

还值得注意的是,虽然从技术上讲,can使用for in循环来逐步完成NSEnumerator,但我发现这实际上抵消了快速枚举的所有速度优势.原因是-countByEnumeratingWithState:objects:count:的默认NSEnumerator实现在每次调用时只在缓冲区中放置一个对象.

我在radar://6296108篇文章中报道了这一点(NSE分子的快速枚举非常缓慢),但它被返回为未修复.原因是快速枚举预先获取一组对象,如果只想枚举到枚举器中的给定点(例如,直到找到特定对象或满足条件),并在中断循环后使用同一个枚举器,通常会跳过多个对象.

如果您是为OS X 10.6/iOS 4.0及以上版本编写代码,您还可以 Select 使用基于块的API枚举数组和其他集合:

[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
    // do something with object
}];

还可以使用-enumerateObjectsWithOptions:usingBlock:和pass NSEnumerationConcurrent和/或NSEnumerationReverse作为选项参数.


10.4或更早

10.5之前的标准习惯用法是使用NSEnumerator和while循环,如下所示:

NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
  // do something with object
}

我建议保持简单.将自己绑定到一个数组类型是不灵活的,而且据称使用-objectAtIndex:的速度增加对10.5+上的快速枚举的改进是微不足道的.(快速枚举实际上在底层数据 struct 上使用指针算法,并消除了大部分方法调用开销.)过早优化从来都不是一个好主意——它会导致更混乱的代码来解决一个不是瓶颈的问题.

使用100时,很容易切换到另一个可枚举集合(如NSSetNSDictionary中的键等),甚至切换到103以向后枚举数组,所有这些都没有其他代码更改.如果迭代代码在一个方法中,您甚至可以传入任何NSEnumerator,代码甚至不必关心它的迭代.此外,只要有更多对象,NSEnumerator(至少是Apple code提供的)就会保留它正在枚举的集合,因此您不必担心自动释放的对象会存在多久.

也许NSEnumerator(或快速枚举)能保护你的最大一件事是在你枚举without your knowledge时,在你的下面有一个可变集合(数组或其他)的改变.如果按索引访问对象,可能会遇到奇怪的异常或一个错误(通常是在问题发生很久之后)导致的错误,这对调试来说可能是可怕的.使用其中一种标准习惯用法的枚举具有"快速失败"行为,因此在发生Mutations 后try 访问下一个对象时,问题(由错误代码引起)将立即显现出来.随着程序变得更加复杂和多线程,甚至依赖于第三方代码可能修改的内容,脆弱的枚举代码变得越来越成问题.封装和抽象FTW!:-)


Objective-c相关问答推荐

Objective-C 中的实例变量是否默认设置为 nil?

协议与类别

CABasicAnimation 无 HUGE_VALF 无限重复?

更改 UIDatePicker 字体 colored颜色 ?

启动 Finder 窗口并 Select 特定文件

NSManagedObjectContext performBlockAndWait:不在后台线程上执行?

在 Xcode 中打破 EXC_BAD_ACCESS?

实现 -hash / -isEqual: / -isEqualTo...: 用于 Objective-C 集合

CF 对象与 NS 对象

在 NSMutableArray 的开头添加一个对象?

在 Objective-C/cocoa 中创建文件夹/目录

如何在情节提要场景中嵌入自定义视图 xib?

字符串的静态 NSArray - 如何/在哪里初始化视图控制器

如何制作真正的私有实例变量?

主队列上的 dispatch_sync 与 dispatch_async

如何从输入 IB 的 UILabel 文本中插入新行 \n?

Cocoapods ld:找不到-lPods-Projectname 的库

在 UITableView 的 iOS 文档目录中列出保存的文件?

Objective-c - CABasicAnimation 在动画后应用更改?

使用 cocoaLumberjack 将日志(log)文件存储在哪里