iOS中集合遍歷方法的比較和技巧

集合的遍歷操作是開發(fā)中最常見的操作之一菩佑,從C語言經(jīng)典的for循環(huán)到利用多核cpu的優(yōu)勢(shì)進(jìn)行遍歷,開發(fā)中ios有若干集合遍歷方法,本文通過研究和測(cè)試比較了各個(gè)操作方法的效率和優(yōu)略勢(shì),并總結(jié)幾個(gè)使用集合遍歷時(shí)的小技巧。

ios中常用的遍歷運(yùn)算方法

遍歷的目的是獲取集合中的某個(gè)對(duì)象或執(zhí)行某個(gè)操作产园,所以能滿足這個(gè)條件的方法都可以作為備選:

經(jīng)典for循環(huán)
for in (NSFastEnumeration),若不熟悉可以參考《nshipster介紹NSFastEnumeration的文章》
makeObjectsPerformSelector
kvc集合運(yùn)算符
enumerateObjectsUsingBlock
enumerateObjectsWithOptions(NSEnumerationConcurrent)
dispatch_apply

實(shí)驗(yàn)

實(shí)驗(yàn)條件

測(cè)試類如下:

@interface Sark : NSObject  
@property (nonatomic) NSInteger number;  
- (void)doSomethingSlow; // sleep(0.01)  
@end

實(shí)驗(yàn)從兩個(gè)方面來評(píng)價(jià):

1夜郁、分別使用有100個(gè)對(duì)象和1000000個(gè)對(duì)象的NSArray什燕,只取對(duì)象,不執(zhí)行操作竞端,測(cè)試遍歷速度

2屎即、使用有100個(gè)對(duì)象的NSArray遍歷執(zhí)行doSomethingSlow方法,測(cè)試遍歷中多任務(wù)運(yùn)行速度

實(shí)驗(yàn)使用CFAbsoluteTimeGetCurrent()記錄時(shí)間戳來計(jì)算運(yùn)行時(shí)間事富,單位秒技俐。

運(yùn)行在iphone5真機(jī)(雙核cpu)

實(shí)驗(yàn)數(shù)據(jù)

100對(duì)象遍歷操作:

經(jīng)典for循環(huán) - 0.001355  
for in (NSFastEnumeration) - 0.002308  
makeObjectsPerformSelector - 0.001120  
kvc集合運(yùn)算符(@sum.number) - 0.004272   
enumerateObjectsUsingBlock - 0.001145  
enumerateObjectsWithOptions(NSEnumerationConcurrent) - 0.001605  
dispatch_apply(Concurrent) - 0.001380 

1000000對(duì)象遍歷操作:

經(jīng)典for循環(huán) - 1.246721  
for in (NSFastEnumeration) - 0.025955  
makeObjectsPerformSelector - 0.068234  
kvc集合運(yùn)算符(@sum.number) - 21.677246  
enumerateObjectsUsingBlock - 0.586034  
enumerateObjectsWithOptions(NSEnumerationConcurrent) - 0.722548  
dispatch_apply(Concurrent) - 0.607100 

100對(duì)象遍歷執(zhí)行一個(gè)很費(fèi)時(shí)的操作:

經(jīng)典for循環(huán) - 1.106567  
for in (NSFastEnumeration) - 1.102643  
makeObjectsPerformSelector - 1.103965  
kvc集合運(yùn)算符(@sum.number) - N/A  
enumerateObjectsUsingBlock - 1.104888  
enumerateObjectsWithOptions(NSEnumerationConcurrent) - 0.554670  
dispatch_apply(Concurrent) - 0.554858 

值得注意的

  1. 對(duì)于集合中對(duì)象數(shù)很多的情況下,for in (NSFastEnumeration)的遍歷速度非常之快统台,但小規(guī)模的遍歷并不明顯(還沒普通for循環(huán)快)
  2. 使用kvc集合運(yùn)算符運(yùn)算很大規(guī)模的集合時(shí)雕擂,效率明顯下降(100萬的數(shù)組離譜的21秒多),同時(shí)占用了大量?jī)?nèi)存和cpu
  3. enumerateObjectsWithOptions(NSEnumerationConcurrent)和dispatch_apply(Concurrent)的遍歷執(zhí)行可以利用到多核cpu的優(yōu)勢(shì)(實(shí)驗(yàn)中在雙核cpu上效率基本上x2)

遍歷實(shí)踐Tips

倒序遍歷

NSArray和NSOrderedSet都支持使用reverseObjectEnumerator倒序遍歷贱勃,如:
NSArray *strings = @[@"1", @"2", @"3"];  
for (NSString *string in [strings reverseObjectEnumerator]) {  
   NSLog(@"%@", string);  
} 

這個(gè)方法只在循環(huán)第一次被調(diào)用井赌,所以也不必?fù)?dān)心循環(huán)每次計(jì)算的問題谤逼。

同時(shí),使用enumerateObjectsWithOptions:NSEnumerationReverse也可以實(shí)現(xiàn)倒序遍歷:

[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(Sark *sark, NSUInteger idx, BOOL *stop) {  
    [sark doSomething];  
}]; 

使用block同時(shí)遍歷字典key仇穗,value

block版本的字典遍歷可以同時(shí)取key和value(forin只能取key再手動(dòng)取value)流部,如:

NSDictionary *dict = @{@"a": @"1", @"b": @"2"};  
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {  
    NSLog(@"key: %@, value: %@", key, obj);  
}]; 

對(duì)于耗時(shí)且順序無關(guān)的遍歷,使用并發(fā)版本

[array enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(Sark *sark, NSUInteger idx, BOOL *stop) {  
    [sark doSomethingSlow];  
}]; 

遍歷執(zhí)行block會(huì)分配在多核cpu上執(zhí)行(底層很可能就是gcd的并發(fā)queue)纹坐,對(duì)于耗時(shí)的任務(wù)來說是很值得這么做的枝冀,而且在以后cpu升級(jí)成更多核心后不用改代碼也可以享受帶來的好處。同時(shí)耘子,對(duì)于遍歷的外部是保持同步的(遍歷都完成后才繼續(xù)執(zhí)行下一行)果漾,猜想內(nèi)部大概是gcd的dispatch_group或者信號(hào)量控制。

代碼可讀性和效率的權(quán)衡

雖然說上面的測(cè)試結(jié)果表明谷誓,在集合內(nèi)元素不多時(shí)绒障,經(jīng)典for循環(huán)的效率要比forin要高,但是從代碼可讀性上來看片林,就遠(yuǎn)不如forin看著更順暢端盆;同樣的還有kvc的集合運(yùn)算符怀骤,一些內(nèi)置的操作以keypath的方式聲明费封,相比自己用for循環(huán)實(shí)現(xiàn),一行代碼就能搞定蒋伦,清楚明了弓摘,還省去了重復(fù)工作;在framework中增加了集合遍歷的block支持后痕届,對(duì)于需要index的遍歷再也不需要經(jīng)典for循環(huán)的寫法了韧献。

References
http://nshipster.com/enumerators/

http://iosdevelopertips.com/objective-c/fast-enumeration-on-the-iphone.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市研叫,隨后出現(xiàn)的幾起案子锤窑,更是在濱河造成了極大的恐慌,老刑警劉巖嚷炉,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渊啰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡申屹,警方通過查閱死者的電腦和手機(jī)绘证,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哗讥,“玉大人嚷那,你說我怎么就攤上這事「松罚” “怎么了魏宽?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵腐泻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我湖员,道長(zhǎng)贫悄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任娘摔,我火速辦了婚禮窄坦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凳寺。我一直安慰自己鸭津,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布肠缨。 她就那樣靜靜地躺著逆趋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪晒奕。 梳的紋絲不亂的頭發(fā)上闻书,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音脑慧,去河邊找鬼魄眉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛闷袒,可吹牛的內(nèi)容都是我干的坑律。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼囊骤,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼晃择!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起也物,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤宫屠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后滑蚯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浪蹂,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年膘魄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乌逐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡创葡,死狀恐怖浙踢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情灿渴,我是刑警寧澤洛波,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布胰舆,位于F島的核電站,受9級(jí)特大地震影響蹬挤,放射性物質(zhì)發(fā)生泄漏缚窿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一焰扳、第九天 我趴在偏房一處隱蔽的房頂上張望倦零。 院中可真熱鬧,春花似錦吨悍、人聲如沸扫茅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽葫隙。三九已至,卻和暖如春躏仇,著一層夾襖步出監(jiān)牢的瞬間恋脚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工焰手, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留糟描,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓册倒,卻偏偏與公主長(zhǎng)得像蚓挤,于是被迫代替她去往敵國(guó)和親磺送。 傳聞我的和親對(duì)象是個(gè)殘疾皇子驻子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容