1. 什么是 RunLoop?
通過系統(tǒng)內(nèi)部維護的事件循環(huán)進行事件/消息管理的一個對象就是 runloop
特點:
- 沒有消息需要處理時,休眠避免資源占用
狀態(tài)切換: 用戶態(tài)->內(nèi)核態(tài),有消息處理時,就是用戶態(tài)的消息處理,而沒有消息時,就托管到系統(tǒng)內(nèi)核本身進行處理 - 有消息需要處理時,立刻被喚醒
狀態(tài)切換:內(nèi)核態(tài)->用戶態(tài)
用戶態(tài):應用程序一般是運行在用戶態(tài)
內(nèi)核態(tài):當我們發(fā)生系統(tǒng)調(diào)用的時候則是在內(nèi)核態(tài)
為什么有用戶態(tài)和內(nèi)核態(tài)?
是因為計算機為了更好的進行資源分配以及調(diào)度,而使系統(tǒng)達到最佳的資源利用,故產(chǎn)生了用戶態(tài)和內(nèi)核態(tài)
為什么 main 函數(shù)能夠保持一直存在且不退出?
在 main 函數(shù)內(nèi)部會調(diào)用 UIApplicationMain 這樣一個函數(shù),而在UIApplicationMain內(nèi)部會啟動主線程的 runloop,因為 runloop 就是通過系統(tǒng)內(nèi)部維護的事件循環(huán)進行事件/消息管理的一個對象,因為可以做到有消息處理時,能夠迅速從內(nèi)核態(tài)到用戶態(tài)的切換,立刻喚醒處理,而沒有消息處理時通過用戶態(tài)到內(nèi)核態(tài)的切換進入等待狀態(tài),避免資源占用。因此 main 函數(shù)能夠一直存在且不退出。
在 OC中系統(tǒng)為我們提供了哪幾種 runloop?
NSRunloop(Foundation),CFRunloop(CoreFoundation)
CFRunloop 的數(shù)據(jù)結(jié)構(gòu)
- CFRunloop
- CFRunloopMode
- Source/Timer/Observer
CFRunloop
- pthread
- currentMode
- modes
- commonModes
- commonModeItems
pthread
- 代表線程,線程和 runloop 是一一對應的
currentMode - CFRunloopMode
modes - 表示的是一個CFRunloopMode的集合
commonModes - 也是一個集合,只是它是一個String 的集合
commonModeItems
- 也是一個集合,里面包含多個 source,多個 timer,多個 observer
CFRunloopMode
- name 當前 mode的名稱
- sources0 集合
- sources1 集合
- observers 數(shù)組
- timers 數(shù)組
CFRunloopSource
- source0 需要手動喚醒線程
- source1 具備主動喚醒線程的能力
CFRunloopTimer
和 NSTimer 是可以免費橋接的
CFRunloopObserver
- 觀測時間點
- kCFRunloopEntry
- kCFRunloopBeforeTimers
- kCFRunloopBeforeSources
- kCFRunloopBeforeWaiting (通知對應觀察者當前 runloop 將要進入休眠狀態(tài)了,系統(tǒng)將從用戶態(tài)切換到內(nèi)核態(tài))
- kCFRunloopAfterWaiting
- kCFRunloopExit
runloop 和 model 以及 source 、 timer、observer 的關(guān)系?
如圖,這是一個一對多的關(guān)系

runloop 的 mode

如圖,runloop 中可以存在多個 mode,每個 mode中有多個 source,observe以及多個 timers,當我們的 runloop 運行在某個 mode中時, 是相互獨立且互不干擾的,當 mode2 中的runloop 接收到回到時,我們運行在 mode 中的 runloop 是不能響應的。
滑動 tableView 的時候,timer 定時器失效了,為什么?
因為 UITableView 的 runloop 默認情況下是運行在 kCFRunloopDefaultMode中,當我們滑動的時候mode切換到UITrackingRunloopMode 中的,而定時器也是運行在 kCFRunloopDefaultMode 中,對應的 observer、timer是沒有辦法進行處理的,所以 timer 會失效,如何解決呢??梢酝ㄟ^ CFRunloopAddTimer函數(shù)把 timer 的 runloop 添加到 commonrunloopmode中,CFRunloopCurrentModes 是系統(tǒng)提供一個將當前 runloopmode添加到多個 mode 的方法,這不是一個真正意義存在的 mode,他是同步 source、observer、timer 到多個 mode 的一種技術(shù)解決方案,當我們調(diào)用CFRunloopAddTimer的時候,系統(tǒng)是會把我們創(chuàng)建的timer同步到UITrackingRunloopMode中的 timers 里面,因此當 tabview 滑動的時候,發(fā)生 mode 的切換,我們的 timer 依舊可以生效。
當一個休眠狀態(tài)的 runloop 我們可以通過哪些方式喚醒?
- timer事件
- source1
- 外部手動喚醒
runloop 事件循環(huán)機制內(nèi)部流程


怎么樣實現(xiàn)一個常駐線程?(三步走)
- 為當前線程添加一個 runloop
- 向添加的 runloop添加一個 port/source 等維持 runloop 的事件循環(huán)
- 啟動 runloop