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

集合的遍歷操作是開發(fā)中最常見的操作之一,從C語(yǔ)言經(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è)方面來(lái)評(píng)價(jià):

分別使用有 100 個(gè)對(duì)象和 1000000 個(gè)對(duì)象的 NSArray酝枢,只取對(duì)象恬偷,不執(zhí)行操作,測(cè)試遍歷速度
使用有 100 個(gè)對(duì)象的 NSArray 遍歷執(zhí)行doSomethingSlow方法帘睦,測(cè)試遍歷中多任務(wù)運(yùn)行速度
實(shí)驗(yàn)使用CFAbsoluteTimeGetCurrent()記錄時(shí)間戳來(lái)計(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

值得注意的

對(duì)于集合中對(duì)象數(shù)很多的情況下竣付,for in (NSFastEnumeration)的遍歷速度非常之快诡延,但小規(guī)模的遍歷并不明顯(還沒普通for循環(huán)快)
使用kvc集合運(yùn)算符運(yùn)算很大規(guī)模的集合時(shí),效率明顯下降(100萬(wàn)的數(shù)組離譜的21秒多)古胆,同時(shí)占用了大量?jī)?nèi)存和cpu
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í)且順序無(wú)關(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ù)來(lái)說是很值得這么做的颊乘,而且在以后cpu升級(jí)成更多核心后不用改代碼也可以享受帶來(lái)的好處参淹。同時(shí),對(duì)于遍歷的外部是保持同步的(遍歷都完成后才繼續(xù)執(zhí)行下一行)乏悄,猜想內(nèi)部大概是gcd的dispatch_group或者信號(hào)量控制浙值。

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

雖然說上面的測(cè)試結(jié)果表明,在集合內(nèi)元素不多時(shí)檩小,經(jīng)典for循環(huán)的效率要比f(wàn)orin要高开呐,但是從代碼可讀性上來(lái)看,就遠(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

轉(zhuǎn)載源地址:blog.sunnyxx.com

最后編輯于
?著作權(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)店門臊泌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鲤桥,“玉大人,你說我怎么就攤上這事渠概〔璧剩” “怎么了?”我有些...
    開封第一講書人閱讀 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)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了叔收?” 一聲冷哼從身側(cè)響起齿穗,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(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
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)奋蔚。三九已至她混,卻和暖如春烈钞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坤按。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(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)容

  • 集合的遍歷操作是開發(fā)中最常見的操作之一留凭,從C語(yǔ)言經(jīng)典的for循環(huán)到利用多核cpu的優(yōu)勢(shì)進(jìn)行遍歷佃扼,開發(fā)中ios有若干...
    hehtao閱讀 102評(píng)論 0 3
  • iOS 中集合遍歷方法的比較和技巧 本文鏈接:http://blog.sunnyxx.com/2014/04/30...
    PanPan1127閱讀 3,969評(píng)論 2 9
  • 1.前言 集合的遍歷操作是開發(fā)中最常見的操作之一,從C語(yǔ)言經(jīng)典的for循環(huán)到利用多核cpu的優(yōu)勢(shì)進(jìn)行遍歷蔼夜,開發(fā)中i...
    火星抄手閱讀 1,092評(píng)論 0 3
  • 哭是懦弱的表現(xiàn)兼耀, 堅(jiān)強(qiáng)是脆弱的偽裝。 不要因別人而改變自己求冷, 不要因他人而磨滅自己高傲的尊嚴(yán)瘤运。
    莫之所以顧錦歌閱讀 191評(píng)論 0 2
  • 1-由于新興技術(shù)快速涌現(xiàn),不斷迭代匠题,專業(yè)和職業(yè)的界限開始模糊拯坟,原有的知識(shí)體系已經(jīng)被打破,有些學(xué)科正在快速地重新構(gòu)建...
    依諾芝閱讀 578評(píng)論 0 1