RunLoop知識點

一癌蚁、概念

RunLoop是通過內(nèi)部維護的事件循環(huán)來對事件/消息進行管理的一個對象

問題1:什么是事件循環(huán)

解釋:

  • 沒有消息需要處理時罗心,休眠以避免資源占用吏砂。


    圖1 線程狀態(tài)切換
  • 有消息處理時,立刻被喚醒拳魁。


    圖2 線程狀態(tài)切換

備注:
內(nèi)核態(tài):在一個進程中惶桐,如果有系統(tǒng)調(diào)用,此時進程處于內(nèi)核態(tài)潘懊;系統(tǒng)操作包括:執(zhí)行文件操作姚糊,網(wǎng)絡(luò)數(shù)據(jù)發(fā)送等操作,此時特權(quán)級別比較高授舟,0級救恨。

用戶態(tài):當一個進程執(zhí)行用戶自己的代碼時,處于用戶態(tài)释树,此時特權(quán)級別比較低肠槽,3級。

小結(jié):
所有用戶程序都是運行在用戶態(tài)的, 但是有時候程序確實需要做一些內(nèi)核態(tài)的事情, 例如執(zhí)行文件操作躏哩,網(wǎng)絡(luò)數(shù)據(jù)發(fā)送等操作署浩。
而唯一可以做這些事情的就是操作系統(tǒng), 所以此時程序就需要先操作系統(tǒng)請求以程序的名義來執(zhí)行這些操作揉燃。

以下是操作系統(tǒng)內(nèi)存空間分布圖:

操作系統(tǒng)分布圖

問題2:為什么main函數(shù)能夠保證不退出

解釋:
1扫尺、在main函數(shù)當中,調(diào)用了UIApplicationMain函數(shù)炊汤。
2正驻、UIApplicationMain函數(shù)會啟動主線程的runloop。
3抢腐、runloop是一個通過事件循環(huán)處理事件/消息的對象姑曙,可以做到“有事做的時候去做事,沒事做的時候從用戶態(tài)切換到內(nèi)核態(tài)迈倍,避免資源的占用伤靠,當前線程是處于一個休眠狀態(tài)”。

//main函數(shù)代碼
int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

二啼染、runloop數(shù)據(jù)結(jié)構(gòu)相關(guān)

2.1宴合、runloop相關(guān)框架

圖3 runloop所在框架

NSRunLoop是CFRunLoop的封裝焕梅,提供了面向?qū)ο蟮腁PI。

2.2卦洽、runloop主要結(jié)構(gòu)

runloop相關(guān)的數(shù)據(jù)結(jié)構(gòu):

  • CFRunLoop
  • CFRunLoopMode
  • Source/Timer/Observer

2.2.1贞言、CFRunLoop

主要包含5個部分

  • pthread
    和線程一一對應(yīng)(RunLoop和線程關(guān)系)

  • currentMode
    CFRunLoopMode類型

  • modes
    NSMutableSet<CFRunLoopMode*>
    mode有多個類型

    • NSDefaultRunLoopMode
      默認mode模型、主線程就在這個模型下
    • UITrackingRunLoopMode
      界面跟蹤mode阀蒂、滑動列表界面
    • NSRunLoopCommonModes
      CommonMode不是實際存在的一種Mode该窗。
      是同步Source/Timer/Observer到多個Model中的一種技術(shù)方案。
    • UIInitializationRunLoopMode
      初始化mode(沒用過)
    • GSEventReceiveRunLoopMode
      系統(tǒng)內(nèi)部mode(沒用過)
  • commonModes
    NSMutableSet<NSString*>
    被打上“common”標記的mode的名稱集合 == NSDefaultRunLoopMode + UITrackingRunLoopMode

  • cmomonModelItems
    Source/Timer/Observer
    如果當前模式是commonModes蚤霞,則會處理cmomonModelItems里面的 Source/Timer/Observer事件酗失。

問題3:RunLoop和線程之間的關(guān)系

解釋:
1、線程和RunLoop之間的關(guān)系是一一對應(yīng)的昧绣。
2级零、主線程的RunLoop是默認開啟的,子線程的RunLoop是默認不開啟的滞乙。
3奏纪、子線程的RunLoop在你主動獲取的情況下,才會創(chuàng)建斩启。
子線程的RunLoop在線程結(jié)束時序调,才會銷毀
主線程除外。

問題4:commonModes的作用

解釋:

  • CommonMode不是實際存在的一種Mode兔簇。
  • 是同步Source/Timer/Observer到多個Model中的一種技術(shù)方案发绢。

2.2.2、CFRunLoopMode

主要包含以下部分:

  • name
    名稱垄琐、默認是NSDefaultRunLoopMode边酒。
  • source0
    NSMutableSet
  • source1
    NSMutableSet
  • observers
    NSMutableArray
  • timers
    NSMutableArray

2.2.3、CFRunLoopSource

  • source0
    需要手動喚醒線程
  • source1
    具備喚醒線程的能力

問題5:source0和source1有什么樣的區(qū)別

解釋
source0需要手動喚醒線程狸窘。
source1具備喚醒線程的能力墩朦。

2.2.3、CFRunLoopTimer

基于事件的定時器
和NSTimer是toll-free bridged (免費橋轉(zhuǎn)換)翻擒。

2.2.4氓涣、CFRunLoopObserver

觀測時間點(共6中狀態(tài))

  • kCFRunLoopEntry
    即將進入Loop
  • kCFRunLoopBeforeTimers
    即將處理 Timer
  • kCFRunLoopBeforeSources
    即將處理 Source
  • kCFRunLoopBeforeWaiting
    即將進入休眠
  • kCFRunLoopAfterWaiting
    剛從休眠中喚醒
  • kCFRunLoopExit
    即將退出Loop

2.2.5、各個數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系

圖4 RunLoop結(jié)構(gòu)關(guān)系

問題6 RunLoop陋气、Model劳吠、Source/Timer/Observer關(guān)系

解釋
RunLoop和Model是一對多的關(guān)系(從CFRunLoop的數(shù)據(jù)結(jié)構(gòu)modes)。
Model和Source/Timer/Observer是一對多的關(guān)系巩趁。

問題7 RunLoop為什么有多個Model

解釋
這樣設(shè)計的原因是為了起到事件屏蔽的效果痒玩。

圖5 Model

當RunLoop運行在Mode1上時,只能接收處理Mode1上的source1、observers蠢古、timers事件回調(diào)燃观,不能接收其它Mode上的source/observer/timer事件回調(diào);起到了事件屏蔽的效果便瑟。

2.2.6缆毁、CommonMode的特殊性

在ios上對應(yīng)的是NSRunLoopCommonModes。

  • CommonMode不是實際存在的一種Mode到涂。
  • 是同步Source/Timer/Observer到多個Model中的一種技術(shù)方案脊框。

三、事件循環(huán)機制(內(nèi)部邏輯)

3.1践啄、整體流程

圖6 事件循環(huán)

1浇雹、在RunLoop啟動后,會發(fā)送一個通知屿讽,告知Observer觀察者昭灵。
2、將要處理Timer/Source0事件伐谈,會發(fā)送一個通知烂完,告知Observer觀察者。
3诵棵、處理Source0事件抠蚣。
4、如果有Source1要處理履澳,會跳過當前流程嘶窄,到第8步。
5距贷、沒有Source1要處理柄冲,線程將要休眠,發(fā)送通知忠蝗。
6现横、休眠,等待喚醒什湘。
7长赞、線程剛被喚醒晦攒。
8闽撤、處理喚醒時收到的消息。

問題8 當一個處于休眠狀態(tài)RunLoop通過哪些事件喚醒它

解釋

  • Source1回調(diào)
  • Timer事件
  • 外部手動喚醒

小結(jié):

點擊App圖標脯颜,從程序啟動哟旗、運行、退出這個過程講解,系統(tǒng)都發(fā)生了什么闸餐?

解釋
1饱亮、程序啟動后,調(diào)用main函數(shù)后舍沙,會調(diào)用UIApplicationmain近上,這UIApplicationmain函數(shù)內(nèi)部會啟動主線程的RunLoop。經(jīng)過一系列處理拂铡,最終主線程RunLoop處于休眠狀態(tài)壹无。
2、此時感帅,點擊一個屏幕斗锭,會產(chǎn)生一個mach_port,基于mach_port最終會轉(zhuǎn)換成一個Source1失球,然后可以喚醒主線程岖是,運行處理事件。
3实苞、當把程序殺死時候豺撑,就會發(fā)生退出RunLoop,發(fā)送通知即將退出RunLoop黔牵,RunLoop退出后前硫,線程也就銷毀掉了。

3.2荧止、RunLoop核心

圖7 RunLoop核心

1屹电、在main函數(shù)中,經(jīng)過一系列處理跃巡,會調(diào)用系統(tǒng)函數(shù)mach_msg()危号,就發(fā)生了系統(tǒng)調(diào)用,這樣會從用戶態(tài)到核心態(tài)
2素邪、在核心態(tài)下面外莲,在一定條件下(Source1/Timer/外部手動喚醒),mach_msg()兔朦,會返回給調(diào)用方偷线,也就是程序從核心態(tài)到用戶態(tài)。

四沽甥、RunLoop與NSTimer

問題9 滑動TableView的時候我們的定時器還會生效嗎声邦?

不會生效
原因:
1、當我們滑動scrollView時摆舟,主線程的RunLoop 會切換到UITrackingRunLoopMode這個Mode亥曹,執(zhí)行的也是UITrackingRunLoopMode下的任務(wù)(Mode中的Source/Timer/Observer)邓了。
2、而timer 是添加在NSDefaultRunLoopMode下的媳瞪,所以timer任務(wù)并不會執(zhí)行骗炉,只有當UITrackingRunLoopMode的任務(wù)執(zhí)行完畢,runloop切換到NSDefaultRunLoopMode后蛇受,才會繼續(xù)執(zhí)行timer句葵。

解決問題:
我們只需要在添加timer 時,將mode 設(shè)置為NSRunLoopCommonModes即可兢仰。

五笼呆、RunLoop與多線程

線程和RunLoop是一一對應(yīng)的
自己創(chuàng)建的線程默認沒有RunLoop的

問題10 怎么實現(xiàn)一個常駐線程

  • 為當前線程開啟一個RunLoop
  • 向RunLoop中添加一個Port/Source等維持RunLoop的事件循環(huán)
  • 啟動該RunLoop
//創(chuàng)建線程
    HLThread *subThread = [[HLThread alloc] initWithTarget:self selector:@selector(subThreadEntryPoint) object:nil];
    [subThread setName:@"HLThread"];
    [subThread start];
//開啟RunLoop
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    //如果注釋了下面這一行,子線程中的任務(wù)并不能正常執(zhí)行
    [runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];
    [runLoop run];

六旨别、面試問題總結(jié)

問題11诗赌、什么是RunLoop,它是怎樣做到有事做事秸弛,沒事休息的铭若?

1、RunLoop是一個通過內(nèi)部循環(huán)對事件/消息進行管理的一個對象递览。
2叼屠、程序運行會調(diào)用main函數(shù),在main函數(shù)里面調(diào)用UIApplicationMain绞铃,UIApplicationMain函數(shù)會啟動主線程的runloop镜雨。
3、runloop運行后儿捧,會調(diào)用系統(tǒng)方法mach_msg()荚坞,會使得程序從用戶態(tài)變成核心態(tài),此時線程處于休眠狀態(tài)菲盾。
4颓影、當有外界條件變化(Source/Timer/Observer),mach_msg會使得程序從核心態(tài)變成用戶態(tài)懒鉴,此時線程處于活躍狀態(tài)诡挂。

問題12、RunLoop與線程是怎么樣的關(guān)系

1临谱、RunLoop與線程是一一對應(yīng)的關(guān)系璃俗。
2、一個線程默認是沒有runloop的(主線程除外)悉默。

問題13城豁、如何實現(xiàn)一個常駐線程

1、為當前線程開啟一個RunLoop
2麦牺、向RunLoop中添加一個Port/Source等維持RunLoop的事件循環(huán)
3钮蛛、啟動該RunLoop

問題14鞭缭、怎樣保證子線程數(shù)據(jù)回來更新UI的時候剖膳,不打斷用戶的滑動操作魏颓?

1、把子線程拋給主線程進行UI更新的邏輯吱晒,可以包裝起來甸饱,提交到主線程的NSDefaultRunLoopMode模式下面。
2仑濒、因為用戶滑動操作是在UITrackingRunLoopMode模式下進行的叹话。

//參考代碼事件
[self.tableView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO modes:@[NSDefaultRunLoopMode]];
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市墩瞳,隨后出現(xiàn)的幾起案子驼壶,更是在濱河造成了極大的恐慌,老刑警劉巖喉酌,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件热凹,死亡現(xiàn)場離奇詭異,居然都是意外死亡泪电,警方通過查閱死者的電腦和手機般妙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來相速,“玉大人碟渺,你說我怎么就攤上這事⊥晃埽” “怎么了苫拍?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長旺隙。 經(jīng)常有香客問我怯疤,道長,這世上最難降的妖魔是什么催束? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任集峦,我火速辦了婚禮,結(jié)果婚禮上抠刺,老公的妹妹穿的比我還像新娘塔淤。我一直安慰自己,他們只是感情好速妖,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布高蜂。 她就那樣靜靜地躺著,像睡著了一般罕容。 火紅的嫁衣襯著肌膚如雪备恤。 梳的紋絲不亂的頭發(fā)上稿饰,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機與錄音露泊,去河邊找鬼喉镰。 笑死,一個胖子當著我的面吹牛惭笑,可吹牛的內(nèi)容都是我干的侣姆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼沉噩,長吁一口氣:“原來是場噩夢啊……” “哼捺宗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起川蒙,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤蚜厉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后畜眨,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昼牛,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年胶果,在試婚紗的時候發(fā)現(xiàn)自己被綠了匾嘱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡早抠,死狀恐怖霎烙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蕊连,我是刑警寧澤悬垃,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站甘苍,受9級特大地震影響尝蠕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜载庭,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一看彼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧囚聚,春花似錦靖榕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至谓松,卻和暖如春星压,著一層夾襖步出監(jiān)牢的瞬間践剂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工娜膘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逊脯,地道東北人。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓劲绪,卻偏偏與公主長得像男窟,于是被迫代替她去往敵國和親盆赤。 傳聞我的和親對象是個殘疾皇子贾富,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

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

  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20150601/11970.html RunL...
    Gatling閱讀 1,436評論 0 13
  • 轉(zhuǎn)自bireme,原地址:https://blog.ibireme.com/2015/05/18/runloop/...
    乜_啊_閱讀 1,344評論 0 5
  • RunLoop 的概念 一般來講牺六,一個線程一次只能執(zhí)行一個任務(wù)颤枪,執(zhí)行完成后線程就會退出。如果我們需要一個機制淑际,讓線...
    Mirsiter_魏閱讀 617評論 0 2
  • 深入理解RunLoop 由ibireme| 2015-05-18 |iOS,技術(shù) RunLoop 是 iOS 和 ...
    橙娃閱讀 849評論 1 2
  • https://blog.ibireme.com/2015/05/18/runloop/ RunLoop 是 iO...
    SmallDe閱讀 693評論 0 51