iOS 块枚举与for循环
来源:互联网 发布:淘宝老客户维护 编辑:程序博客网 时间:2024/06/05 01:15
在编程中经常需要列举collection中得元素,在当前的Objective-C语言中又多重办法实现此功能,可以用C语言循环,也可以用Objective-C 1.0中得NSEnumerator以及Objective-C 2.0的快速便利(fast enumeration)。在引入了“block”之后,又多出来了集中的的遍历方式。下面详细说明。
for循环
NSArray *anArray = /*...*/; for (int i = 0; i < anArray.count; i++) { id object = anArray[i]; //Do something with 'object' }
这么写还好,不过如果要便利字典或者set,就要复杂一点了:
//Dictionary NSDictionary *aDictionary = /*...*/; NSArray *keys = [aDictionary allKeys]; for (int i = 0; i < keys.count; i++) { id key = keys[i]; id value = aDictionary[key]; //Do something with 'key' and 'value' }
//Set NSSet *aSet = /*...*/; NSArray *objects = [aSet allObjects]; for (int i = 0; i < objects.count; i++) { id object = objects[i]; //Do something with 'object' }
for循环也可以实现反向遍历,计数器的值从“元素个数减1”,每次迭代时递减直到0为止。执行反向遍历时,使用for循环会比其它方式简单许多。
用Objective-C 1.0中的 NSEnumerator 来遍历NSEnumerator 是个抽象基类,其中只定义了两个方法,供其具体子类来实现:
-(NSAraay *)allObjects;- (id)nextObject;
Foundation框架中内建的collection类都实现了这种遍历方式。例如,想遍历数组,可以这样写代码:
NSArray *anArray = /* ... */; NSEnumerator *enumerator = [anArray objectEnumerator]; id object; while ((object = [enumerator nextObject]) != nil) { // Do something with 'object' }这种写法的功能与标准的for循环相似,但是代码却多了一些。其真正优势在于:不论遍历哪种collection,都可以采用这套相似的语法。比方说,遍历字典及set时也可以按照这种写法来做:
// Dictionary NSDictionary *aDictionary = /* ... */; NSEnumerator *enumerator = [aDictionary keyEnumerator]; id key; while ((key = [enumerator nextObject]) != nil) { id value = aDictionary[key]; // Do something with 'key' and 'value' }
// Set NSSet *aSet = /* ... */; NSEnumerator *enumerator = [aSet objectEnumerator]; id object; while ((object = [enumerator nextObject]) != nil) { // Do something with 'object' }
NSArray *anArray = /* ... */; NSEnumerator *enumerator = [anArray reverseObjectEnumerator]; id object; while ((object = [enumerator nextObject]) != nil) { // Do something with 'object' }与采用for 循环的等效写法相比,上面这段代码读起来更顺畅。
快速遍历
Objective-C 2.0引入了快速遍历这一功能。快速遍历与使用NSEnumerator来遍历差不多,然而语法更简洁,它为for循环开设了in关键字。这个关键字大幅简化了遍历collection所需的语法,比方说要遍历数组,就可以这么写:
NSArray *anArray = /* ... */; for (id object in anArray) { // Do something with 'object' }这样写简单多了。如果某个类的对象支持快速遍历,那么就可以宣称自己遵从名为NSFastEnumeration的协议,从而令开发者可以采用此语法来迭代该对象。此协议只定义了一个方法:
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id*)stackbuffer count:(NSUInteger)length;该方法的工作原理不在本条目所述范围内。不过网上能找到一些优秀的教程,它们会把这个问题解释的很清楚,其要点在于:
遍历字典与set也很简单:
// Dictionary NSDictionary *aDictionary = /* ... */; for (id key in aDictionary) { id value = aDictionary[key]; // Do something with 'key' and 'value' }
// Set NSSet *aSet = /* ... */; for (id object in aSet) { // Do something with 'object' }
由于NSEnumerator对象也实现了NSFastEnumeration协议,所以能用来执行反向遍历数组,可采用下面这种写法:
NSArray *anArray = /* ... */; for (id object in [anArray reverseObjectEnumerator]) { // Do something with 'object' }
基于block的遍历方式
在当前的Objective-C 语言中美最新引入的一种做法就是基于block来遍历。NSArray中定义了下面这个方法,它可以实现最基本的遍历功能:
- (void)enumerateObjectsUsingBlock:(void(^)(id object, NSUInteger idx, BOOL *stop))block;
在遍历数组及set时,每次迭代都要执行由block参数所传入的块,这个块有三个参数,分别是当前迭代所针对的对象、所针对的下标,以及指向布尔值的指针。前两个参数的含义不言而喻。而通过第三个参数所提供的机制,开发者可以终止遍历操作。
例如,下面这段代码用此方法来遍历数组:
NSArray *anArray = /* ... */; [anArray enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) { // Do something with 'object' if (shouldStop) { *stop = YES; } }];
此方式不仅可用来遍历数组。NSSet里面也有同样的块枚举方法,NSDictionary也是这样,只是略有不同:
- (void)enumerateKeysAndObjectsUsingBlock:(void(^)(id key, id object, BOOL *stop))block;因此,遍历字典与set也同样简单:
// Dictionary NSDictionary *aDictionary = /* ... */; [aDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) { // Do something with 'key' and 'object' if (shouldStop) { *stop = YES; } }];
// Set NSSet *aSet = /* ... */; [aSet enumerateObjectsUsingBlock:^(id object, BOOL *stop) { // Do something with 'object' if (shouldStop) { *stop = YES; } }];
另外一个好处是,能够修改block的方法名,以免进行类型转换的操作,从效果上讲,相当于把本来需要执行的类型转换操作交给block方法签名来做。比方说,要用“快速遍历法”来遍历字典。若已知字典中得对象必为字符串,则可以这样编码:
NSDictionary *aDictionary = /* ... */; for (NSString *key in aDictionary) { NSString *object = (NSString*)aDictionary[key]; // Do something with 'key' and 'object' }
如果改用基于block的方式来遍历,那么就可以在block方法签名中直接转换:
[aDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) { // Do something with 'key' and 'obj' }];
用此方式也可以执行反向遍历。数组、字典、set都实现了前述方法的另一个版本,使开发者可向其传入“选项掩码”(option mask):
- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)options usingBlock:(void(^)(id obj, NSUInteger idx, BOOL *stop))block;- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)options usingBlock: (void(^)(id key, id obj, BOOL *stop))block;
NSEnumerationOptions类型是个enum,其各种取值可用“按位或”(bitwise OR)连接,用以表明遍历方式。例如,开发者可以请求以冰法方式执行各轮迭代,也就是说,如果当前系统资源状况允许,那么执行每次迭代所用的block就可以并行执行了。通过NSEnumerationConcurrent选项即可开启此功能。如果使用此选项,那么底层会通过GCD来处理冰法执行事宜,具体实现时很可能会用到dispatch group。不过,到底如何来实现,不是本条索要讨论的内容。反向遍历是通过 NSEnumerationReverse选项来实现的。要注意:只有遍历数组或有序set等有顺序的collection时,这么做才有意义。
总体来看,block枚举法拥有其他遍历方式都具备的优势,而且还能带来更多好处。与快速遍历法相比,它要多用一些代码,可是却能提供遍历时所针对的下标,在,在遍历字典时也能同时提供键与值,而且还有选项可以开启并发迭代功能,所以多写这点代码还是值得的。
要点
■遍历collection有四种方式。最基本的方法是for循环,其次是NSEnumerator遍历法及快速遍历法,最新最先进的的方式则是“block枚举法”。
■“block枚举法”本身就能通过GCD来并发执行遍历操作,无需另行编写代码。而采用其他遍历方式则无法轻易实现这一点。
■若提前知道待遍历的collection含有何种对象,则应修改block签名,指出具体类型。
链接:http://www.jianshu.com/p/f76e8c62a755
來源:简书
- iOS 块枚举与for循环
- 块枚举,for循环
- 多用块枚举,少用for循环
- 多用块枚举,少用for循环
- 黑马程序员--增强for循环与 枚举
- 写高质量OC代码52建议总结:48.多用块枚举,少用for循环
- 静态导入,可变参数,枚举与增强型for循环
- IOS第二天_循环与跳出,以及块
- 双重for循环语句块的优化
- for循环程序块的处理顺序
- smarty模板:section循环块与foreach循环块
- IOS块与多线程
- 静态导入、枚举、增强for循环
- scala的for循环 :枚举的“瑞士军刀”
- for循环与while循环
- for循环 与 while循环
- iOS 与 位移枚举
- for循环与 for/in循环
- Git查看、删除、重命名远程分支和tag
- JavaScript语句
- beeline连接hiveserver2源码分析
- 动态链接库给传入指针赋值,调试时有可能调试器会欺骗你。
- AAAAAAAAAAAAAAAA
- iOS 块枚举与for循环
- error:Operation not allowed after ResultSet closed
- 对集合进行排序
- C#关键字--修饰符
- AngularJS入门-(6)表达式
- JavaScript 变量
- 个人比较感兴趣的android开源项目
- scala断言专栏--选择项目的测试样式
- GRADLE自定义你的BUILDCONFIG