做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:1000002012-08-02 17:14:22.062 otest[388:303] MULogTimeintervalBegin:ArrayTest2012-08-02 17:14:22.075 otest[388:303]for statement:0.0131082012-08-02 17:14:22.083 otest[388:303]for-in:0.0081862012-08-02 17:14:22.095 otest[388:303] enumerateBlock:0.012290Test Case '-[LoopTestTests testArray]' passed (0.165 seconds).Test Case '-[LoopTestTests testDictionary]' started.2012-08-02 17:14:22.273 otest[388:303] init:1000002012-08-02 17:14:22.274 otest[388:303] MULogTimeintervalBegin:DictionaryTest2012-08-02 17:14:22.284 otest[388:303] for statement allValues:0.0105662012-08-02 17:14:22.307 otest[388:303] for statement allKeys:0.0223772012-08-02 17:14:22.330 otest[388:303] enumeration:0.023914Test 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]]; } |