源碼解讀RunLoop,理解以后面試必加分

繼上一篇博客

中高級iOS必備知識點之RunLoop(一)繼續(xù)介紹

RunLoop的狀態(tài)

首先我們?nèi)unLoop的源碼去查看它有幾種狀態(tài),如下圖:

它一共有上面的這幾種個狀態(tài)

/* Run Loop Observer Activities */

typedef?CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {

kCFRunLoopEntry = (1UL << 0), //即將進入loop

kCFRunLoopBeforeTimers = (1UL << 1), //即將處理timer

kCFRunLoopBeforeSources = (1UL << 2), //即將處理source

kCFRunLoopBeforeWaiting = (1UL << 5), //即將進入休眠

kCFRunLoopAfterWaiting = (1UL << 6), //剛從休眠中喚醒

kCFRunLoopExit = (1UL << 7), //即將退出loop

kCFRunLoopAllActivities = 0x0FFFFFFFU //所有模式

};

現(xiàn)在我們來試一試,怎么去監(jiān)聽RunLoop的狀態(tài),是這樣,RunLoop的監(jiān)聽模式?jīng)]有OC的代碼,我們可以用C語言代碼來實現(xiàn),如下:

從執(zhí)行的結果來看,確實是這么多,點擊事件是在source0執(zhí)行,所以看log日志也是很清楚,

接下來我們看一下定時器喚醒RunLoop.我們知道kCFRunLoopBeforeWaiting是休眠睡覺,而kCFRunLoopAfterWaiting是喚醒休眠,我們看一下定時器是不是喚醒休眠,請看下面的代碼:

從輸出結果來看,確實是喚醒休眠.執(zhí)行block

證明模式切換會退出RunLoop,再重新進入RunLoop

由上面的監(jiān)聽,我們是很容易可以證明這個結果吧?我們看一下代碼,這次用上面說的另一種創(chuàng)建observe的方法,請看下圖:隨便創(chuàng)建一個可以滾動的view,比如我創(chuàng)建的Scrollerview.

當在滾動的時候,我們明顯可以看到2種模式在切換,而且RunLoop也是需要退出重新進入才會切換到新的模式.

深入理解RunLoop的執(zhí)行流程

網(wǎng)上的答案很多,這次我們從源碼解析,一步一步的查看RunLoop的執(zhí)行流程到底是怎么樣的:因為源碼比較抽象,是純c語言的,不像我們之前的有c++源碼比較好懂一點,那我們怎么找runloop開始的函數(shù)呢?很容易,我們知道點擊也是通過runloop來處理的,那我們直接看點擊事件的函數(shù)調(diào)用棧就知道入口了,請看下圖:

從上面的代碼可以很清楚的看出來是調(diào)用了CFRunLoopRunSpecific這個函數(shù).那我們就去源碼搜索這段代碼很容易就搜索到.請看下面:

一看上面的源碼,我們發(fā)現(xiàn)執(zhí)行了非常多,你看綠色里面有鎖,有多線程等等,所以我們沒有必要研究得很透徹,浪費時間也沒有意義,我們只要把大致流程捋順了就行了,所以我們只要看關鍵代碼,我只展示我們要看的關鍵代碼如下:

接下來我們就去看__CFRunLoopRun源碼里面到底執(zhí)行了哪些操作,接下來的源碼是我精簡了的,大家可以參照源碼看一下,因為里面東西非常多,我們沒有必要全部了解,只要知道它的執(zhí)行流程即可.請看下圖:

如果條件不成立,就會設置返回值,到時候直接退出RunLoop,上面的流程相信我備注的已經(jīng)非常清楚,對照一下源碼看一下,你會印象更加深刻.下面我們用文字總結一下流程如下:

再放一個文字版的:

這個和源碼基本一模一樣的流程,可以參照一下,源碼還是比較抽象的

接下來再看一個知識點.

__CFRunLoopDoBlocks拆又、__CFRunLoopDoObservers冤议、__CFRunLoopDoTimers里面執(zhí)行了什么

其中RunLoop做了這么幾件大事中比如blocks,timers,observers,我們看下里面具體是執(zhí)行了什么,繼續(xù)看源碼,請看下圖,比如我們就看__CFRunLoopDoSources0:

其實最終處理的就是這個:

__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__

我們再看下之前的一個截圖

它上面兩個處理的函數(shù)是一摸一樣,也進一步的證明了,觸摸事件是source0在處理.

定時器也是一樣的道理,大家可以自己嘗試一下.

理解線程休眠具體是什么意思?

RunLoop的線程休眠是真的休眠,它是不會占用任何cpu的資源,完全休息.它和white(1)這種還是有本質(zhì)的區(qū)別,white(1)它是一直在執(zhí)行,轉(zhuǎn)成匯編會有幾條指令,一直在執(zhí)行,一直占用cpu資源,比如我們想做優(yōu)化,那RunLoop的這種休眠模式是不是更節(jié)約cpu資源,說白了更省電些.就是如下源碼的位置:

就是執(zhí)行到當前代碼,就不會往下走了,不會接著執(zhí)行下面的代碼,就會堵在這里,一旦別人喚醒它了,它才會接著往下執(zhí)行.我們可能奇怪它是怎么做到的這種休眠?

我們看一下里面具體是怎么實現(xiàn)的,其實里面是執(zhí)行了非常內(nèi)核的函數(shù)叫做:mach_msg,我們可以看下

其實IPA可以分為內(nèi)核層面的IPA:它是非常非常底層的,是操作系統(tǒng)層面的,它可以讓線程休眠,也是真的休眠,不占用任何cpu資源,一般是不開放給我們程序員使用的,因為是比較內(nèi)核的,給程序員使用危險也比較大,而應用層面的IPA,都是網(wǎng)絡請求什么,頁面什么.

所以mach_msg,我們面試的時候可以答出這個函數(shù).

RunLoop休眠實現(xiàn)的原理

就是用戶態(tài)和內(nèi)核態(tài)的切換,用戶態(tài)發(fā)消息,內(nèi)核態(tài)休眠,再被喚醒,用戶態(tài)處理消息.

所以如果面試官問:RunLoop里面線程阻塞是怎么樣的?我們千萬不能答,里面是個死循環(huán).就是上面剛剛說的那些.

RunLoop與NSTimer的故事

相信我們在開發(fā)中遇到的次數(shù)是非常的多,這里稍微提一下.

比如我們常見的mode模式是有2種

1.KCFRunLoopDefaultMode (NSDefaultRunLoopMode):App的默認Mode,通常是主線程是在這個Mode下運行

2.UITrackingRunLoopMode : 界面跟蹤Mode,用于ScrollView追蹤觸摸滑動,保證界面滑動時不受其他Mode影響

我們在把Timer添加到runloop的時候,直接傳入通用模式即可NSRunLoopCommonModes即可.

主要說一下它是怎么個原因.

我們看一下上個博客說的RunLoop的結構:

我們可以理解為傳入NSRunLoopCommonModes,就是把這2種模式,放入_commonModes里面,也就是timer可以_commonModes數(shù)組中的模式下進行工作.注意NSRunLoopCommonModes這個不是一種模式哈.

而_commonModeItems里面存放的都是可以在_commonModes模式下工作的,比如剛剛的timer.

接下來我會繼續(xù)介紹'線程倍疲活'知識點.

如果覺得我寫得對您有所幫助肩碟,請關注我礁芦,我會持續(xù)更新??

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市方咆,隨后出現(xiàn)的幾起案子浸船,更是在濱河造成了極大的恐慌,老刑警劉巖疗韵,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兑障,死亡現(xiàn)場離奇詭異,居然都是意外死亡蕉汪,警方通過查閱死者的電腦和手機流译,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來者疤,“玉大人福澡,你說我怎么就攤上這事【月恚” “怎么了革砸?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長糯累。 經(jīng)常有香客問我算利,道長,這世上最難降的妖魔是什么泳姐? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任效拭,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘缎患。我一直安慰自己借笙,他們只是感情好,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布较锡。 她就那樣靜靜地躺著业稼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚂蕴。 梳的紋絲不亂的頭發(fā)上低散,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機與錄音骡楼,去河邊找鬼熔号。 笑死,一個胖子當著我的面吹牛鸟整,可吹牛的內(nèi)容都是我干的引镊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼篮条,長吁一口氣:“原來是場噩夢啊……” “哼弟头!你這毒婦竟也來了?” 一聲冷哼從身側響起涉茧,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赴恨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伴栓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伦连,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年钳垮,在試婚紗的時候發(fā)現(xiàn)自己被綠了惑淳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡饺窿,死狀恐怖歧焦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情短荐,我是刑警寧澤倚舀,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站忍宋,受9級特大地震影響痕貌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜糠排,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一舵稠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦哺徊、人聲如沸室琢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盈滴。三九已至,卻和暖如春轿钠,著一層夾襖步出監(jiān)牢的瞬間巢钓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工疗垛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留症汹,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓贷腕,卻偏偏與公主長得像背镇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子泽裳,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

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