本質(zhì)
RunLoop本質(zhì)上是一個對象,這個對象可以保持程序的持續(xù)運行并且處理程序中的各種事件(如觸摸事件,定時器時間,selector事件).
RunLoop沒有事情處理時就會使線程進入睡眠狀態(tài).這樣可以節(jié)省CPU資源,提高程序性能.
和線程的關(guān)系
線程用來執(zhí)行一個或者多個任務,執(zhí)行完成后就會退出,再有任務也無法繼續(xù)執(zhí)行。
runloop,讓線程不斷的執(zhí)行任務,當沒有任務的時候,進入休眠狀態(tài),等待任務的到來。
每條線程都有唯一的一個RunLoop對象。
RunLoop保存在一個全局的 Dictionary里,線程作為key, RunLoop作為 value。
線程剛創(chuàng)建時并沒有 RunLoop對象, RunLoop會在第一次獲取它時創(chuàng)建。
RunLoop會在線程結(jié)束時銷毀。
主線程的 RunLoop已經(jīng)自動獲取,子線程默認沒有開啟 Runloop。
底層數(shù)據(jù)結(jié)構(gòu)
RunLoop的數(shù)據(jù)結(jié)構(gòu)主要有三種:
CFRunLoop、CFRunLoopMode、Source/Timer/Observer

CFRunLoop.png

CFRunLoopMode.png

Source:Timer:Observer.png
幾種運行模式(mode)?每個運行模式下面的 CFRunloopMode 是哪些?他們分別是什么職責?
- kCFRunLoopDefaultMode:App的默認Mode,通常主線程是在這個Mode下運行
- UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響
- UIInitializationRunLoopMode: 在剛啟動 App 時第進入的第一個 Mode,啟動完成后就不再使用,會切換到kCFRunLoopDefaultMode
- GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到
- kCFRunLoopCommonModes: 這是一個占位用的Mode,作為標記kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一種真正的Mode
監(jiān)聽狀態(tài)有哪幾種
- kCFRunLoopEntry:RunLoop進入運行循環(huán)狀態(tài)。
- kCFRunLoopExit:RunLoop退出運行循環(huán)狀態(tài)。
- kCFRunLoopBeforeTimers:RunLoop即將處理定時器事件。
- kCFRunLoopBeforeSources:RunLoop即將處理事件源事件。
- kCFRunLoopBeforeWaiting:RunLoop即將進入睡眠等待狀態(tài)。
- kCFRunLoopAfterWaiting:RunLoop被喚醒并處理完事件后即將進入下一個循環(huán)狀態(tài)。
- kCFRunLoopAllActivities:監(jiān)聽所有狀態(tài)。
工作流程

流程.png
- 通知 observer,進入runloop
- 通知 observer,即將處理 timer 事件
- 通知 observer,即將處理 source 事件
- 處理block,runloop 是可以添加 block 的(CFRunLoopPerformBlock(<#CFRunLoopRef rl#>, <#CFTypeRef mode#>, <#^(void)block#>))
- 處理 source 0
- 處理 source1事件,如果存在就處理,跳轉(zhuǎn)到第8
- 通知 observer 即將休眠
- 通知 observer 結(jié)束休眠(timer 事件,source1 事件等)
- 然后根據(jù)前面的執(zhí)行結(jié)果,決定是否再次循環(huán)
應用場景
保證線程的長時間存活
滾動視圖流暢性優(yōu)化
讓Timer正常運轉(zhuǎn)
事件響應、手勢識別、界面刷新、AutoreleasePool自動釋放池、NSTimer、PerformSelecter、GCD、網(wǎng)絡請求底層等都用到了RunLoop