//第一种
[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循环的写法了。