文章出處

做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語法會對容器里面的元素的內存地址建立一個緩沖,遍歷的時候從緩沖直接取得元素的地址而不是通過調用方法來獲取,所以效率比較高。另外,這也是不能在循環體中修改容器元素的原因之一。


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()