《编写高质量代码:改善Objective-C程序的61个建议》——建议13:在访问集合时要优先考虑使用快速枚举

简介:

本节书摘来自华章出版社《编写高质量代码:改善Objective-C程序的61个建议》一 书中的第2章,作者:刘一道,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

建议13:在访问集合时要优先考虑使用快速枚举

在Objective-C语言中,集合是最常用的数据类型。而对于集合的访问,要优先考虑使用快速枚举。使用快速枚举,要尽可能使用枚举新的写法。

  1. 尽可能使用枚举新的写法
    使用Objective-C新的枚举写法,编写更简洁的代码,同时避免一些常见的陷阱。更重要的是,这些语法特性是完全向下兼容的,使用新特性编写出来的代码经过编译后形成的二进制程序可以运行在之前发布的任何OS中。

在使用枚举新的写法之前,先梳理一下最近几年来枚举类型几次功能的改进。
枚举在OS X 10.5 之前的版本中,如何在Objective-C中定义一个枚举类型呢?定义方法如下:

typedef enum { 
   ObjectiveC,
   Java, 
   Ruby, 
   Python, 
   Erlang }
Language;

这种写法简单明了,用起来也不复杂,但是有一个问题,就是其枚举值的数据范围是模糊的,这个数值可能非常大,可能是负数,无法界定。
在OS X 10.5之后的版本中,就可以这样写:

enum {
   ObjectiveC,
   Java,
   Ruby,
   Python,
   Erlang
};
typedef NSUInteger Language;

这种写法的好处是,首先这个枚举的数据类型是确定的,无符号整数;其次,由于采用了 NSUInteger,就可以不用考虑32位和64位的问题。但这样写所带来的问题是,数据类型和枚举常量没有显式的关联。
在XCode 4.4中,就可以这样写枚举了:

typedef enum Language : NSUInteger{
   ObjectiveC,
   Java, 
   Ruby, 
   Python, 
   Erlang 
}Language;

在列出枚举内容的同时绑定了枚举数据类型NSUInteger,这样带来的好处是增强了类型检查和更好的代码可读性。
当然,对于普通开发者来说,枚举类型可能不会涉及复杂的数据,使用之前的两种写法也不会有什么大问题,但还是建议使用枚举新的写法,以增强现在写的代码在未来中有更强的适用性。
上面介绍了为何尽可能使用枚举新的写法,下面将介绍枚举在集合中的应用。
Objective-C和Cocoa 或 Cocoa Touch提供了多种方式来枚举集合的内容。虽然它可以使用传统的C 循环来遍历内容,像这样:

int count = [array count];
for (int index = 0; index < count; index++) {
  id eachObject = [array objectAtIndex:index];
  ...
}

这时最好的做法是使用本节中描述的其他技术之一。

  1. 理解快速枚举
    快速枚举是一种语言中用于快速安全的枚举一个集合的表达式,下面将从快速枚举的定义及其应用来分别介绍。

for…in表达式,这种快速枚举表达式是如下定义的:

for ( Type newVariable in expression ) { statements }
或者:
Type existingItem;
for ( existingItem in expression ) { statements }

这两种表达式中,expression是一个遵守NSFastEnumeration协议的对象。每次循环被迭代的对象都会返回一个对象并赋给一个循环变量,同时statements中定义的代码被执行一次。当被迭代的对象中已经没有数据可以取出时,循环变量被设为nil,如果循环在这之前被停止,那么循环变量会指向最后一次返回的值。

  1. 使用快速枚举可以很容易地枚举集合
    许多集合类遵照了NSFastEnumeration协议,如 Foundation 中的集合类NSArray、 NSDic-tionary和 NSSet。显而易见,枚举操作可以遍历NSArray和NSSet的内容。对于其他类,相关文档会说明哪些内容会被枚举。例如,NSDictionary和NSManagedObjectModel也支持快速枚举,但是NSDictionary枚举的是它的键值,NSManagedObjectModel枚举的是它的实体。

作为一个例子,可以使用快速枚举,像这样在一个数组记录每个对象的描述:

for (id eachObject in array) {
  NSLog(@"Object: %@", eachObject);
}

变量eachObject被自动设置为每个通过循环到当前对象,所以,一个日志报表显示每个对象。如果使用快速枚举字典,可以快速遍历字典键,像这样:

for (NSString *eachKey in dictionary) {
  id object = dictionary[eachKey];
  NSLog(@"Object: %@ for key: %@", object, eachKey);
}

快速枚举的行为很像一个标准的C 循环,这样就可以使用打破关键字来中断迭代,或继续前进到下一个元素。如果枚举有序的集合,枚举按顺序来进行。对于一个NSArray,这意味着第一次将索引为 0,第二个对象在索引1处,等等。如果需要跟踪当前索引,只需迭代计数,因为它们发生:

int index = 0;
   for (id eachObject in array) {
       NSLog(@"Object at index %i is: %@", index, eachObject);
       index++;
}

在快速枚举集合期间,不能变异集合,即使集合是可变的。如果从循环内,尝试添加或删除集合的对象,则会生成运行时异常。

  1. 大多数集合也支持枚举器对象
    也可以通过使用 NSEnumerator 对象枚举Cocoa和Cocoa Touch中的许多集合。例如,对于objectEnumerator 或 reverseObjectEnumerator,可以查询NSArray。快速枚举可以使用这些对象,像这样:
for (id eachObject in [array reverseObjectEnumerator]) {
  ...
}

在此示例中,循环将按照相反的顺序来让变数可以递回取得集合的对象,所以最后一个对象将是第一个,等等。通过反复调用枚举的nextObject的方法,它也可以遍历这些内容,像这样:

id eachObject;
while ( (eachObject = [enumerator nextObject]) ) {
  NSLog(@"Current object is: %@", eachObject);
}

在这个例子中,一个while 循环用于将 eachObject 变量设置为每次循环的下一个对象。当没有更多的对象保留时,nextObject方法将返回nil,评估为false的逻辑值,以使循环停止。
 当想表达相等运算符(==)时,程序员常见的错误是使用C 赋值运算符 (=) ,如果在一个条件分支或循环中设置一个变量,这样将会造成编译器发出警告,像这样:

if (someVariable = YES) {
    ...
}

如果真的这样做意味着重新分配一个变量(整体转让的逻辑值是左侧的最终值),可以将括号中的分配,像这样:

if ( (someVariable = YES) ) {
    ...
}

与快速枚举一样,在枚举进行时不可改变集合。而且,可根据名字来进行收集,使用快速枚举,相比使用手动枚举对象更快。
 要点
(1)使用快速枚举,要尽可能使用枚举新的写法。
(2)和直接使用NSEnumerator相比,使用快速枚举可以更有效率,表达式更简洁。
(3)使用快速枚举,枚举更安全,因为枚举会监控枚举对象的变化,如果在枚举的过程中枚举对象发生变化会抛出一个异常。
(4)多个枚举可以同时进行,因为在循环中被循环对象是禁止修改的。另外,同其他的循环一样,可以使用break来停止循环或者使用continue来略过当次循环而进行到下一元素。

相关文章
|
2月前
|
API iOS开发 开发者
Snapchat API 访问:Objective-C 实现示例
Snapchat API 访问:Objective-C 实现示例
|
3月前
|
开发工具 iOS开发 容器
【Azure Blob】关闭Blob 匿名访问,iOS Objective-C SDK连接Storage Account报错
【Azure Blob】关闭Blob 匿名访问,iOS Objective-C SDK连接Storage Account报错
|
4月前
|
开发工具 iOS开发 容器
【Azure Blob】关闭Blob 匿名访问,iOS Objective-C SDK连接Storage Account报错
iOS Objective-C 应用连接Azure Storage时,若不关闭账号的匿名访问,程序能正常运行。但关闭匿名访问后,上传到容器时会出现错误:“Public access is not permitted”。解决方法是将创建容器时的公共访问类型从`AZSContainerPublicAccessTypeContainer`改为`AZSContainerPublicAccessTypeOff`,以确保通过授权请求访问。
【Azure Blob】关闭Blob 匿名访问,iOS Objective-C SDK连接Storage Account报错
|
JSON 开发工具 iOS开发
Objective-C使用位运算设计可复选的枚举
Objective-C使用位运算设计可复选的枚举
125 0
Objective-C使用位运算设计可复选的枚举
|
JSON 开发工具 iOS开发
Objective-C使用位运算设计可复选的枚举
 在软件开发中,枚举是我们会经常会用到的一种编程方式,通过枚举,可以使我们的代码更具可读性与统一性。通常情况下,我们会通过typedef来定义一种枚举的类型来使用
193 0
|
iOS开发
Objective-C中通过下标的方式访问自定义数据模型中属性
Objective-C中通过下标的方式访问自定义数据模型中属性
149 0
|
Shell Linux C语言
Windows 下使用 GNUstep 编译并运行 Objective-C 程序
今晚上开始看《Objective-C 程序设计(第4版)》这本书(OSChina 正在做此书的书评活动,详情请看这里),到现在为止看到第 7 章,于是想动手试试写两简单的程序编译跑跑看。
1441 0
|
程序员 iOS开发
《编写高质量代码:改善Objective-C程序的61个建议》——导读
我一直在思考,如何才能编写出高质量、优秀的代码,我也在不停地探寻,希望找出类似于武侠小说中所说的武功秘籍,在编写代码一途可以帮助大家走“捷径”从而达到事半功倍的效果。
1091 0
|
存储 C语言 iOS开发
Objective-C官方文档 值和集合
版权声明:原创作品,谢绝转载!否则将追究法律责任。 尽管Objective-c是一个面向对象的语言,是C语言的超集,这意味着你可以用任何标准的C标量(非对象)像int,float,和char在Objective-c里面。
933 0
下一篇
无影云桌面