哪种遍历NSArray/NSDictionary方式快?

做app的时候,总免不了要多次遍历数组或者字典。

究竟哪种遍历方式比较快呢?我做了如下测试:

首先定义测试用宏:

#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:

- (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:

- (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:

for (NSInteger i = 0; i < count; ++i) {
        [sum appendString:[testArray objectAtIndex:i]];
    }
这里由于存在:[objectAtIndex:i]这样的取操作,所以速度会有所下降。

for(NSString* item in testArray) {
        [sum appendString:item];
    }
尽管也有取操作,但是绕开了oc的message机制,速度会快一点。也有可能是编译器为了for-in作了优化。

block为什么会慢一些这个有待研究。

NSDictionary:

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

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

=================================================================================

google了一下,stackoverflow上面有类似的讨论:点击打开链接

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值