淺析Runloop

有一定iOS開(kāi)發(fā)經(jīng)驗(yàn)的人可能都聽(tīng)說(shuō)過(guò)RunLoop网缝。RunLoop,顧名思義蟋定,就是run loop 粉臊,跑圈的意思。

Apple對(duì)Runloop是這么解釋的:

The NSRunLoop class declares the programmatic interface to objects that manage input sources. An NSRunLoop object processes input for sources such as mouse and keyboard events from the window system, NSPort objects, and NSConnection objects. An NSRunLoop object also processes NSTimer events.

?
簡(jiǎn)單的驶兜,Runloop可以理解為一個(gè)事件循環(huán)扼仲,循環(huán)中執(zhí)行不同的代碼,直到進(jìn)入下一次循環(huán)的條件不足為止抄淑!

Runloop不是線(xiàn)程屠凶,不是GCD,而是一個(gè)對(duì)象肆资,在一個(gè)APP里面不是唯一的矗愧。

下面的這個(gè)圖介紹了代碼執(zhí)行最常見(jiàn)的兩種方式,命令式和event驅(qū)動(dòng)的迅耘。其中一個(gè)是一次執(zhí)行到底贱枣,而另外一個(gè)是反復(fù)不停地進(jìn)行某一個(gè)行為监署,也就是跑圈颤专。


runloop_1

RunLoop就是事件驅(qū)動(dòng)模型的代表。這種模型被稱(chēng)作 Event Loop钠乏。 Event Loop 在很多系統(tǒng)和框架里都有實(shí)現(xiàn)栖秕,比如 Node.js 的事件處理,比如 Windows 程序的消息循環(huán)晓避,再比如 OSX/iOS 里的 RunLoop簇捍。實(shí)現(xiàn)這種模型的關(guān)鍵點(diǎn)在于:如何管理事件/消息只壳,如何讓線(xiàn)程在沒(méi)有處理消息時(shí)休眠以避免資源占用、在有消息到來(lái)時(shí)立刻被喚醒暑塑。

所以吼句,RunLoop 實(shí)際上就是一個(gè)對(duì)象,這個(gè)對(duì)象管理了其需要處理的事件和消息事格,并提供了一個(gè)入口函數(shù)來(lái)執(zhí)行上面 Event Loop 的邏輯惕艳。線(xiàn)程執(zhí)行了這個(gè)函數(shù)后,就會(huì)一直處于這個(gè)函數(shù)內(nèi)部 "接受消息->等待->處理" 的循環(huán)中驹愚,直到這個(gè)循環(huán)結(jié)束(比如傳入 quit 的消息)远搪,函數(shù)返回。

OSX/iOS 系統(tǒng)中逢捺,提供了兩個(gè)這樣的對(duì)象:NSRunLoopCFRunLoopRef谁鳍。
CFRunLoopRef 是在 CoreFoundation 框架內(nèi)的,它提供了純 C 函數(shù)的 API劫瞳,所有這些 API 都是線(xiàn)程安全的倘潜。而NSRunLoop 是基于CFRunLoopRef的封裝,提供了面向?qū)ο蟮?API柠新,但是這些 API 不是線(xiàn)程安全的窍荧。CoreFoundationFoundation對(duì)象在A(yíng)RC中處理也是不一樣的。所以使用RunLoop的時(shí)候一定要小心恨憎。

Apple 在RunLoop的介紹里還特別強(qiáng)調(diào)了下:

The NSRunLoop class is generally not considered to be thread-safe and its methods should only be called within the context of the current thread. You should never try to call the methods of an NSRunLoop object running in a different thread, as doing so might cause unexpected results.

雖然我們無(wú)法創(chuàng)建RunLoop蕊退,但是Apple給我們提供了兩個(gè)自動(dòng)獲取的函數(shù):CFRunLoopGetMain()CFRunLoopGetCurrent()

線(xiàn)程和 RunLoop 之間是一一對(duì)應(yīng)的,一個(gè)線(xiàn)程只能有唯一對(duì)應(yīng)的runloop憔恳,但這個(gè)runloop里可以嵌套子runloop瓤荔,然后把他們之間的關(guān)系保存在一個(gè)全局的 Dictionary 里。線(xiàn)程剛創(chuàng)建時(shí)并沒(méi)有 RunLoop钥组,如果你不主動(dòng)獲取输硝,那它一直都不會(huì)有。RunLoop 的創(chuàng)建是發(fā)生在第一次獲取時(shí)程梦,RunLoop 的銷(xiāo)毀是發(fā)生在線(xiàn)程結(jié)束時(shí)点把。你只能在一個(gè)線(xiàn)程的內(nèi)部獲取其 RunLoop(主線(xiàn)程除外)

下面介紹一點(diǎn)稍深入點(diǎn)的知識(shí)
先上圖


runloop_2

RunnLoop有幾個(gè)運(yùn)行狀態(tài)下的Mode

  1. kCFRunLoopDefaultMode: App的默認(rèn) Mode,通常主線(xiàn)程是在這個(gè) Mode 下運(yùn)行的屿附。
  2. UITrackingRunLoopMode: 界面跟蹤 Mode郎逃,用于 ScrollView 追蹤觸摸滑動(dòng),保證界面滑動(dòng)時(shí)不受其他 Mode 影響挺份,提高用戶(hù)體驗(yàn)褒翰。
  3. UIInitializationRunLoopMode: 在剛啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode,啟動(dòng)完成后就不再使用。
  4. GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 -
  5. kCFRunLoopCommonModes: 這是一個(gè)占位的 Mode优训,沒(méi)有實(shí)際作用朵你。

一個(gè) RunLoop 包含若干個(gè) Mode,每個(gè) Mode 又包含若干個(gè) Source/Timer/Observer揣非。每次調(diào)用 RunLoop 的主函數(shù)時(shí)抡医,只能指定其中一個(gè) Mode,這個(gè)Mode被稱(chēng)作 CurrentMode早敬。如果需要切換 Mode魂拦,只能退出 Loop,再重新指定一個(gè) Mode 進(jìn)入搁嗓。這樣做主要是為了分隔開(kāi)不同組的 Source/Timer/Observer芯勘,讓其互不影響。
?
Source/Timer/Observer 被統(tǒng)稱(chēng)為 mode item腺逛,一個(gè) item 可以被同時(shí)加入多個(gè) mode荷愕。但一個(gè) item 被重復(fù)加入同一個(gè) mode 時(shí)是不會(huì)有效果的。如果一個(gè) mode 中一個(gè) item 都沒(méi)有棍矛,則 RunLoop 會(huì)直接退出安疗,不進(jìn)入循環(huán)。

這里還有個(gè)概念叫 CommonModes够委,一個(gè) Mode 可以將自己標(biāo)記為Common荐类。每當(dāng) RunLoop 的內(nèi)容發(fā)生變化時(shí),RunLoop 都會(huì)自動(dòng)將 CommonMode Items 里的 Source/Observer/Timer 同步到有 Common 標(biāo)記的所有Mode里茁帽。

我們?cè)陂_(kāi)發(fā)中經(jīng)常會(huì)用到定時(shí)器玉罐,如果細(xì)心點(diǎn)就會(huì)發(fā)現(xiàn),timer在你滑動(dòng)的時(shí)候就會(huì)被停止潘拨,當(dāng)滑動(dòng)結(jié)束的時(shí)候才會(huì)繼續(xù)吊输。這就是因?yàn)閙ode不同造成的。我們可以把timer也加到滑動(dòng)專(zhuān)用的trackingMode中去铁追,這樣timer就可以在滑動(dòng)的時(shí)候保持繼續(xù)運(yùn)行季蚂!

詳解:
在主線(xiàn)程的 RunLoop 里有兩個(gè)預(yù)置的 Mode:kCFRunLoopDefaultModeUITrackingRunLoopMode。這兩個(gè) Mode 都已經(jīng)被標(biāo)記為 Common 屬性琅束。DefaultMode 是 App 默認(rèn)狀態(tài)下所處的狀態(tài)扭屁,TrackingRunLoopMode 是追蹤滑動(dòng)時(shí)的狀態(tài)。當(dāng)你創(chuàng)建一個(gè) Timer 并加到 DefaultMode 時(shí)涩禀,Timer 會(huì)得到重復(fù)回調(diào)料滥,但此時(shí)滑動(dòng)一個(gè)滾動(dòng)視圖時(shí),RunLoop 會(huì)將 mode 切換為 TrackingRunLoopMode埋泵,這時(shí) Timer 就不會(huì)被回調(diào)幔欧,并且也不會(huì)影響到滑動(dòng)操作。如果將這個(gè) Timer 分別加入這兩個(gè) Mode丽声,或者將 Timer 加入到頂層的 RunLoop 的 CommonMode Items 中礁蔗。CommonModeItems 被 RunLoop 自動(dòng)更新到所有具有 Common 屬性的 Mode 里去。這樣就解決了Timer的回調(diào)問(wèn)題雁社。

還有一個(gè)RunLoop對(duì)象類(lèi)型浴井,叫做CFRunLoopObserverRef。它就是RunLoop的觀(guān)察者霉撵,每一個(gè)observer都需要指定一個(gè)回調(diào)函數(shù)的指針磺浙,在當(dāng) RunLoop 的狀態(tài)發(fā)生變化時(shí),觀(guān)察者就能通過(guò)回調(diào)接受到這個(gè)變化徒坡。
RunLoop的狀態(tài)有這么幾個(gè)

kCFRunLoopBeforeTimers--------------------------------即將處理Timer
kCFRunLoopBeforeSources-------------------------------即將處理Source
kCFRunLoopBeforeWaiting-------------------------------即將進(jìn)入休眠
kCFRunLoopAfterWaiting--------------------------------剛從休眠中喚醒
kCFRunLoopExit----------------------------------------即將退出Loop

有個(gè)很出名的cell自動(dòng)計(jì)算行高的高性能三方框架就是利用這個(gè)做的優(yōu)化撕氧! 利用RunLoop即將進(jìn)入休眠的間隙去做一些耗時(shí)的運(yùn)算,可以大幅減少數(shù)據(jù)刷新的整體耗時(shí)喇完,提高用戶(hù)體驗(yàn)伦泥!

小Tips:
初學(xué)iOS的時(shí)候,很多人會(huì)有疑問(wèn)锦溪,被標(biāo)記了autorelease的對(duì)象究竟在什么時(shí)候釋放了不脯?到了RunLoop這里就有了答案。RunLoopBeforeWaiting時(shí)刻诊,將這次Loop中產(chǎn)生的autorelease對(duì)象釋放防楷!

最后提供一些資料:

  1. sunnyxx的RunLoop線(xiàn)下分享
  2. 深入理解RunLoop
  3. CFRunLoopRef源碼
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市则涯,隨后出現(xiàn)的幾起案子复局,更是在濱河造成了極大的恐慌,老刑警劉巖粟判,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肖揣,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡浮入,警方通過(guò)查閱死者的電腦和手機(jī)龙优,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)事秀,“玉大人彤断,你說(shuō)我怎么就攤上這事∫准#” “怎么了宰衙?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)睹欲。 經(jīng)常有香客問(wèn)我供炼,道長(zhǎng)一屋,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任袋哼,我火速辦了婚禮冀墨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涛贯。我一直安慰自己诽嘉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布弟翘。 她就那樣靜靜地躺著虫腋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪稀余。 梳的紋絲不亂的頭發(fā)上悦冀,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音睛琳,去河邊找鬼雏门。 笑死,一個(gè)胖子當(dāng)著我的面吹牛掸掏,可吹牛的內(nèi)容都是我干的茁影。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼丧凤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼募闲!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起愿待,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤浩螺,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后仍侥,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體要出,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年农渊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了患蹂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡砸紊,死狀恐怖传于,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情醉顽,我是刑警寧澤沼溜,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站游添,受9級(jí)特大地震影響系草,放射性物質(zhì)發(fā)生泄漏通熄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一找都、第九天 我趴在偏房一處隱蔽的房頂上張望唇辨。 院中可真熱鬧,春花似錦檐嚣、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至隐解,卻和暖如春鞍帝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背煞茫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工帕涌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人续徽。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓蚓曼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親钦扭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子纫版,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

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

  • RunLoop的概念 一般來(lái)講,一個(gè)線(xiàn)程一次只能執(zhí)行一個(gè)任務(wù)客情,執(zhí)行完成后線(xiàn)程就會(huì)退出其弊。如果我們需要一個(gè)機(jī)制,讓線(xiàn)程...
    IOS學(xué)渣閱讀 461評(píng)論 1 4
  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20150601/11970.html RunL...
    Gatling閱讀 1,438評(píng)論 0 13
  • 前言 最近離職了,可以盡情熬夜寫(xiě)點(diǎn)總結(jié)膀斋,不用擔(dān)心第二天上班爽并蛋疼著梭伐,這篇的主角 RunLoop 一座大山,涵蓋的...
    zerocc2014閱讀 12,376評(píng)論 13 67
  • 原文地址:http://blog.ibireme.com/2015/05/18/runloop/ RunLoop ...
    大餅炒雞蛋閱讀 1,158評(píng)論 0 6
  • 上一貼說(shuō)到T+0仰担。很多人說(shuō)操作有難度糊识,容易T飛。我自己也T飛過(guò)摔蓝,還不止一次技掏,總結(jié)為啥?除了功課做的不到位项鬼,最重要是...
    愛(ài)美麗大妞愛(ài)思考閱讀 237評(píng)論 0 3