//第一种 [arr
enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop){ NSLog(@ "%ld,%@" ,idx,[arr
objectAtIndex:idx]); }]; //第二种 dispatch_apply([arr
count], dispatch_get_global_queue( 0 ,
0 ),
^(size_t index){ //并行 NSLog(@ "%ld,%@" ,index,[arr
objectAtIndex:index]); }); //第三种 dispatch_apply([arr
count], dispatch_get_main_queue(), ^(size_t index){ //串行,容易引起主线程堵塞,可以另外开辟线程 NSLog(@ "%ld,%@" ,index,[arr
objectAtIndex:index]); }); //第四种 for
(NSString*str in arr) { NSLog(@ "%@" ,str); } //第五种,do-while int
i = 0 ; do
{ NSLog(@ "%@" ,[arr
objectAtIndex:i]); i++; }
while
(i<[arr count]); //第六种,while-do int
j = 0 ; while
(j<[arr count]) { NSLog(@ "%@" ,[arr
objectAtIndex:j]); j++; } //第七种,普通for循环 for
( int
m = 0 ;
m<[arr count]; m++) { NSLog(@ "%@" ,[arr
objectAtIndex:m]); } |
① 其中第二种方法由于是并行,所以打印出来的东西是随机的,并不是按照顺序打印的
② 第三种容易引起主线程堵塞,所以最好自己另外创建一个线程
倒序遍历
NSArray
和NSOrderedSet
都支持使用reverseObjectEnumerator
倒序遍历,如:
1 2 3 4 |
NSArray *strings = @[@"1", @"2", @"3"]; for (NSString *string in [strings reverseObjectEnumerator]) { NSLog(@"%@", string); } |
这个方法只在循环第一次被调用,所以也不必担心循环每次计算的问题。
同时,使用enumerateObjectsWithOptions:NSEnumerationReverse
也可以实现倒序遍历:
1 2 3 |
[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(Sark *sark, NSUInteger idx, BOOL *stop) {
[sark doSomething];
}];
|
使用block同时遍历字典key,value
block版本的字典遍历可以同时取key和value(forin只能取key再手动取value),如:
1 2 3 4 |
NSDictionary *dict = @{@"a": @"1", @"b": @"2"}; [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { NSLog(@"key: %@, value: %@", key, obj); }]; |
对于耗时且顺序无关的遍历,使用并发版本
1 2 3 |
[array enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(Sark *sark, NSUInteger idx, BOOL *stop) {
[sark doSomethingSlow];
}];
|
遍历执行block会分配在多核cpu上执行(底层很可能就是gcd的并发queue),对于耗时的任务来说是很值得这么做的,而且在以后cpu升级成更多核心后不用改代码也可以享受带来的好处。同时,对于遍历的外部是保持同步的(遍历都完成后才继续执行下一行),猜想内部大概是gcd的dispatch_group或者信号量控制。
代码可读性和效率的权衡
虽然说上面的测试结果表明,在集合内元素不多时,经典for循环的效率要比forin要高,但是从代码可读性上来看,就远不如forin看着更顺畅;同样的还有kvc的集合运算符,一些内置的操作以keypath
的方式声明,相比自己用for循环实现,一行代码就能搞定,清楚明了,还省去了重复工作;在framework中增加了集合遍历的block支持后,对于需要index的遍历再也不需要经典for循环的写法了。