周遊清單應該是平時開發中最常見的一種操作了。說起周遊效率,相比于其他方面的因素(可維護性,易懂等),也許周遊的效率在你的代碼中并不是那麼重要。
但我們還是要了解一下從性能方面去考慮周遊這個問題,以便在一寫特殊的case下知道怎麼着手去優化。
下面是幾種常用的周遊方式:
1. for (NSInteger i = 0 ; i < len; i++)
2. for ( NSObject * o bj in Array)
3. - (void)enumerateObjectsUsingBlock:(void (NS_NOESCAPE ^)(ObjectType obj, NSUInteger idx, BOOL *stop))block
4. dispatch_apply( size_t iterations, dispatch_queue_t queue,
DISPATCH_NOESCAPE void (^block)(size_t));
5.NSEnumerator
1. 我們最常用的周遊方式
2. 快速周遊,這種寫法在 寫法上更直接明了,可以直接拿到數組中的元素
3. 蘋果提供的block塊周遊, 有以下特點:
1. 索引和元素均可以傳回,其他隻傳回元素
2. 并發枚舉,也不是說并發就一定高效,當有大量的任務去做的時候,在多核處理器下,對性能的提升比較明顯,相反,要是任務很小,它帶來的好處可能并不大,在性能比較重要的場景可以試驗權衡。
4. Index 順序不确定,因為它是并行執行的(dispatch_get_global_queue是并行隊列)。這裡 dispatch_apply如果換成串行隊列上,則會依次輸出index。
dispathc_apply 是dispatch_sync 和dispatch_group的關聯API.它以指定的次數将指定的Block加入到指定的隊列中。并等待隊列中操作全部完成。
5. 每次被調用時會生成NSEnumerator執行個體,并指向第一個元素,和連結清單next指針一樣,nextObject方法傳回下一個元素,直到元素為nil止。
下面看代碼,我們目标是擷取到每個元素:
- (void)loop_test
{
NSArray *sampleItemArray = [self itemArray];
CFTimeInterval startTime = CFAbsoluteTimeGetCurrent();
// - - - - - - - - - - - --- - - -- - -- -- - - - -- - -- -
NSInteger len = [sampleItemArray count];
for (NSInteger i = 0 ; i < len; i++){
NSObject *obj = sampleItemArray[i];
}
NSLog(@"common for-in loop: %.8f", CFAbsoluteTimeGetCurrent() - startTime);
// - - - - - - - - - - - --- - - -- - -- -- - - - -- - -- -
startTime = CFAbsoluteTimeGetCurrent();
for (NSObject *obj in sampleItemArray){
}
NSLog(@"fast for-in loop: %.8f", CFAbsoluteTimeGetCurrent() - startTime);
// - - - - - - - - - - - --- - - -- - -- -- - - - -- - -- -
startTime = CFAbsoluteTimeGetCurrent();
[sampleItemArray enumerateObjectsUsingBlock:^(NSObject * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
}];
NSLog(@"enumerate-block loop: %.8f", CFAbsoluteTimeGetCurrent() - startTime);
// - - - - - - - - - - - --- - - -- - -- -- - - - -- - -- -
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
startTime = CFAbsoluteTimeGetCurrent();
dispatch_apply([sampleItemArray count], queue, ^(size_t index) {
NSObject *obj = sampleItemArray[index];
});
NSLog(@"dispatch_apply loop: %.8f", CFAbsoluteTimeGetCurrent() - startTime);
// - - - - - - - - - - - --- - - -- - -- -- - - - -- - -- -
NSObject *obj = nil;
startTime = CFAbsoluteTimeGetCurrent();
NSEnumerator *enumerator = [sampleItemArray objectEnumerator];
while ((obj = [enumerator nextObject])) {
}
NSLog(@"NSEnumerator loop: %.8f", CFAbsoluteTimeGetCurrent() - startTime);
}
列印結果:
common for loop: 0.00076401
fast for-in loop: 0.00004494
enumerate-block loop: 0.00093901
dispatch_apply loop: 0.00052500
NSEnumerator loop: 0.00072098
結論分析:資料來看 1. 性能最優 的是快速枚舉for-in
2. enumerate-block性能最差,是快速枚舉的近20倍。
3. NSEnumerator和普通的for循環差别不大,是apply的1.4倍