在說RunLoop之前,先來了解一下iOS的系統(tǒng)架構(gòu),蘋果官方將整個系統(tǒng)大致分為四個層次---應(yīng)用層,應(yīng)用架構(gòu)層,核心架構(gòu)層和Darwin。Mach是Darwin的組成部分,Mach提供的API非常的少,但這些API非常的基礎(chǔ),如果沒有這些API的話,其他的任何工作是無法實施的。(廢話嗎,寫在操作系統(tǒng)核心的東西能不基礎(chǔ)么)。而RunLoop的核心其實就是mach_msg(),如果沒有別人發(fā)送 port 消息過來,內(nèi)核會將線程置于等待狀態(tài)。
一般來說,一個線程一次只能執(zhí)行一個任務(wù),執(zhí)行完成后線程就會退出,那么加入我們點開一個應(yīng)用,執(zhí)行一次后就不能再執(zhí)行了,而我們需要的是,當(dāng)我們再次點擊時,程序仍然可以相應(yīng)我們的操作,這就需要一個機(jī)制,讓線程可以隨時處理事件而且不退出。邏輯很簡單,只是一個循環(huán)就可以了,實現(xiàn)這種模型的關(guān)鍵點在于:如何管理事件/消息,如何讓線程在沒有處理消息時休眠以避免資源占用、在有消息到來時立刻被喚醒。
RunLoop實際上是一個對象,這個對象管理了其需要處理的消息。并提供了一個入口函數(shù)來執(zhí)行它的邏輯。線程執(zhí)行了這個函數(shù)后,就會一直處于這個函數(shù)內(nèi)部 "接受消息->等待->處理" 的循環(huán)中,直到這個循環(huán)結(jié)束(比如傳入 quit 的消息),函數(shù)返回。
蘋果是不允許我們直接創(chuàng)建RunLoop的,它給我們提供了兩個函數(shù),CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。從字面意思就可以看出,一個是獲取主RunLoop,一個是獲取當(dāng)前的RunLoop。線程和 RunLoop 之間是一一對應(yīng)的,其關(guān)系是保存在一個全局的 Dictionary 里。線程作為Key,RunLoop作為value,線程剛創(chuàng)建時并沒有 RunLoop,如果你不主動獲取,那它一直都不會有。RunLoop 的創(chuàng)建是發(fā)生在第一次獲取時,RunLoop 的銷毀是發(fā)生在線程結(jié)束時。你只能在一個線程的內(nèi)部獲取其 RunLoop。
RunLoop有一個類叫CFRunLoopModeRef,蘋果為我們提供了這個類的API,一個RunLoop可以有很多個Mode,每次調(diào)用 RunLoop 的主函數(shù)時,只能指定其中一個 Mode,這個Mode被稱作 CurrentMode。我們最常見的是kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。DefaultMode 是默認(rèn)狀態(tài)的,TrackingRunLoopMode 是追蹤 ScrollView 滑動時的狀態(tài)。我們非常常見的一種狀態(tài)有創(chuàng)建一個Timer,把這個Timer加入到DefaultMode里,當(dāng)Scrollview或者其子類進(jìn)行滑動時,Timer就會停止,就是因為Scrollview在滑動時,RunLoop 將 mode 切換為了 TrackingRunLoopMode。
再來談一下我對AutoReleasepool和RunLoop的一些關(guān)系。在App啟動以后,蘋果在主線程RunLoop里會注冊兩個Observe,一個Observe監(jiān)視的事件是即將進(jìn)入Loop,另一個observe監(jiān)視的是即將進(jìn)入休眠和退出Loop,在第一個observe在回調(diào)內(nèi)會調(diào)用 _objc_autoreleasePoolPush() 創(chuàng)建自動釋放池。其 order 是-2147483647,優(yōu)先級最高,保證創(chuàng)建釋放池發(fā)生在其他所有回調(diào)之前。第二個 Observer在 BeforeWaiting(準(zhǔn)備進(jìn)入休眠) 時調(diào)用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 釋放舊的池并創(chuàng)建新池;在Exit(即將退出Loop) 時調(diào)用 _objc_autoreleasePoolPop() 來釋放自動釋放池。這個 Observer 的 order 是 2147483647,優(yōu)先級最低,保證其釋放池子發(fā)生在其他所有回調(diào)之后。這也就保證了我們在主線程里寫的一些代碼會永遠(yuǎn)被RunLoop創(chuàng)建好的Autoreleasepool包圍著,避免的內(nèi)存的泄露,同時也方便了我們開發(fā)者。實際上 RunLoop 底層也會用到 GCD 的東西,比如 RunLoop 是用 dispatch_source_t 實現(xiàn)的 Timer。但同時 GCD 提供的某些接口也用到了 RunLoop, 例如 dispatch_async()。
參考文章:http://www.cocoachina.com/cms/wap.php?action=article&id=11970
我對RunLoop的一點理解
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- Run loop 剖析:Runloop 接收的輸入事件來自兩種不同的源:輸入源(intput source)和定時...