oc/object-c/ios哪种遍历NSArray/NSDictionary方式快?测试报告

做app的时候,总免不了要多次遍历数组或者字典。
究竟哪种遍历方式比较快呢?我做了如下测试:
首先定义测试用宏:

?
1
2
3
4
5
6
7
8
9
#define MULogTimeintervalBegin(INFO) NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];\
NSTimeInterval duration = 0;\
NSLog (@ "MULogTimeintervalBegin:%@" , INFO)
 
#define MULogTimeintervalPauseAndLog(INFO) duration = [NSDate timeIntervalSinceReferenceDate] - start;\
start += duration;\
NSLog (@ "%@:%f" , INFO, duration);\
duration = 0
#define TESTSCALE 100000



接着编写测试代码:
NSarray:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- ( void )testArray
{
     NSMutableArray * testArray = [ NSMutableArray arrayWithCapacity:TESTSCALE];
     for ( NSInteger i = 1; i <= TESTSCALE; ++i) {
         [testArray addObject:[ NSString stringWithFormat:@ "%ld" , i]];
     }
     NSLog (@ "init:%ld" , [testArray count]);
     
     __block NSMutableString * sum = [ NSMutableString stringWithCapacity:TESTSCALE];
     
     MULogTimeintervalBegin(@ "ArrayTest" );
     NSUInteger count = [testArray count];
     for ( NSInteger i = 0; i < count; ++i) {
         [sum appendString:[testArray objectAtIndex:i]];
     }
     [sum setString:@ "" ];
     MULogTimeintervalPauseAndLog(@ "for statement" );
     
     for ( NSString * item in testArray) {
         [sum appendString:item];
     }
     [sum setString:@ "" ];
     MULogTimeintervalPauseAndLog(@ "for-in" );
     
     [testArray enumerateObjectsUsingBlock:^( id obj, NSUInteger idx, BOOL *stop) {
         [sum appendString:obj];
     }];
     [sum setString:@ "" ];
     MULogTimeintervalPauseAndLog(@ "enumerateBlock" );
}


NSDictionary:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- ( void )testDictionary {
     NSMutableDictionary * testDic = [ NSMutableDictionary dictionaryWithCapacity:TESTSCALE];
     for ( NSInteger i = 1; i <= TESTSCALE; ++i) {
         [testDic setObject:@ "test" forKey:[ NSString stringWithFormat:@ "%ld" , i]];
     }
     NSLog (@ "init:%ld" , [testDic count]);
     
     __block NSMutableString * sum = [ NSMutableString stringWithCapacity:TESTSCALE];
     
     MULogTimeintervalBegin(@ "DictionaryTest" );
     for ( NSString * object in [testDic allValues]) {
         [sum appendString:object];
     }
     [sum setString:@ "" ];
     MULogTimeintervalPauseAndLog(@ "for statement allValues" );
     
     for ( id akey in [testDic allKeys]) {
         [sum appendString:[testDic objectForKey:akey]];
     }
     [sum setString:@ "" ];
     MULogTimeintervalPauseAndLog(@ "for statement allKeys" );
     
     [testDic enumerateKeysAndObjectsUsingBlock:^( id key, id obj, BOOL *stop) {
         [sum appendString:obj];
     } ];
     MULogTimeintervalPauseAndLog(@ "enumeration" );
}



下面是测试结果:
Test Case '-[LoopTestTests testArray]' started.
2012-08-02 17:14:22.061 otest[388:303] init:100000
2012-08-02 17:14:22.062 otest[388:303] MULogTimeintervalBegin:ArrayTest
2012-08-02 17:14:22.075 otest[388:303]for statement:0.013108
2012-08-02 17:14:22.083 otest[388:303]for-in:0.008186
2012-08-02 17:14:22.095 otest[388:303] enumerateBlock:0.012290
Test Case '-[LoopTestTests testArray]' passed (0.165 seconds).
Test Case '-[LoopTestTests testDictionary]' started.
2012-08-02 17:14:22.273 otest[388:303] init:100000
2012-08-02 17:14:22.274 otest[388:303] MULogTimeintervalBegin:DictionaryTest
2012-08-02 17:14:22.284 otest[388:303] for statement allValues:0.010566
2012-08-02 17:14:22.307 otest[388:303] for statement allKeys:0.022377
2012-08-02 17:14:22.330 otest[388:303] enumeration:0.023914
Test Case '-[LoopTestTests testDictionary]' passed (0.217 seconds).

可以看出对于数组来说,for-in方式遍历速度是最快的,普通风格的for和block方式速度差不多。对于字典来说,allValues方式遍历最快,allKeys和block差不多。
那么,为什么会这样呢?
NSArray:

?
1
2
3
for ( NSInteger i = 0; i < count; ++i) {
         [sum appendString:[testArray objectAtIndex:i]];
}


这里由于存在:[objectAtIndex:i]这样的取操作,所以速度会有所下降。

?
1
2
3
for ( NSString * item in testArray) {
         [sum appendString:item];
}


尽管也有取操作,但是绕开了oc的message机制,速度会快一点。也有可能是编译器为了for-in作了优化。
block为什么会慢一些这个有待研究。
NSDictionary:

?
1
2
3
for ( id akey in [testDic allKeys]) {
         [sum appendString:[testDic objectForKey:akey]];
}


这个就很明显了,第二种方法多了一次objectForKey的操作。block的话有待研究。



google了一下,stackoverflow上面有类似的讨论:点击打开链接
大意是:for-in语法会对容器里面的元素的内存地址建立一个缓冲,遍历的时候从缓冲直接取得元素的地址而不是通过调用方法来获取,所以效率比较高。另外,这也是不能在循环体中修改容器元素的原因之一。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值