原文鏈接:NSRunLoop簡(jiǎn)介
RunLoop的作用
- 程序持續(xù)運(yùn)行的保證,如果RunLoop不存在了,程序也就結(jié)束運(yùn)行了。
- 在循環(huán)中處理各種事件,如觸摸事件、定時(shí)器事件、Selector事件。
- 節(jié)省CPU的資源,在需要執(zhí)行任務(wù)的時(shí)候被喚醒,當(dāng)沒(méi)有任務(wù)執(zhí)行的時(shí)候進(jìn)入休眠狀態(tài)。
程序啟動(dòng)的流程
- 執(zhí)行main函數(shù)
- 執(zhí)行UIApplicationMain函數(shù)
- 指定UIApplication對(duì)象
- 指定UIApplication的代理
- 創(chuàng)建UIApplication對(duì)象,并且指定它的代理。
- 創(chuàng)建一個(gè)主運(yùn)行循環(huán)(RunLoop),這是一個(gè)死循環(huán),保證程序的持續(xù)運(yùn)行。
- 加載配置了所有應(yīng)用程序信息的info.plist文件
- 應(yīng)用程序啟動(dòng)完畢
NSRunLoop和CFRunLoopRef
- CFRunLoopRef是在CoreFoundation框架中的,它的內(nèi)部API以及實(shí)現(xiàn),都是純C語(yǔ)言編寫(xiě),這些API都是線程安全的。
- NSRunLoop是基于CFRunLoopRef的封裝,它提供了面向?qū)ο蟮腁PI,但是這些API不是線程安全的。
- 這兩個(gè)對(duì)象的地址不同,因?yàn)樗鼈兊膶?duì)象來(lái)自于完全不同的類(lèi)。
- CFRunLoop可以調(diào)用getCfRunLoop方法,將NSRunLoop轉(zhuǎn)化為CFRunLoop。
RunLoop與線程
- 每一條線程,都有一個(gè)與之相對(duì)應(yīng)的RunLoop對(duì)象,負(fù)責(zé)處理線程中的任務(wù)。
- 主線程和RunLoop:RunLoop在程序已經(jīng)啟動(dòng)的時(shí)候就創(chuàng)建好了
- 子線程和RunLoop:
- 子線程會(huì)單獨(dú)開(kāi)啟RunLoop去執(zhí)行任務(wù)
- 子線程和RunLoop是一一對(duì)應(yīng)的關(guān)系,每個(gè)子線程都有自己的RunLoop(但需要主動(dòng)創(chuàng)建)
- 創(chuàng)建子線程的RunLoop:
[NSRunloop currentRunLoop] - 子線程的RunLoop需要手動(dòng)開(kāi)啟:
[[NSRunLoop currentRunLoop] run]
RunLoopMode
-
RunLoop的運(yùn)行模式
- 一個(gè)RunLoop至少要指定一個(gè)運(yùn)行模式,當(dāng)運(yùn)行模式指定之后,至少有一個(gè)Source或者Timer任務(wù)在執(zhí)行。
- RunLoop啟動(dòng)之后,只能指定一個(gè)運(yùn)行模式,可以使用currentMode來(lái)獲取。
- 如果要切換RunLoop的運(yùn)行模式,就要先退出當(dāng)前的RunLoop,重新指定Mode再次進(jìn)入運(yùn)行。
-
系統(tǒng)默認(rèn)注冊(cè)的5個(gè)Mode
- kCFRunLoopDefaultMode App的默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行的。
- UITrackingRunLoopMode 界面跟蹤Mode,用于ScrollView/TableView等追蹤觸摸滑動(dòng),保證界面滑動(dòng)的時(shí)候不受其他Mode影響。
- UIInitializationRunLoopMode 當(dāng)App啟動(dòng)時(shí),第一個(gè)進(jìn)入的Mode,啟動(dòng)完成之后就不會(huì)再使用這個(gè)Mode。
- GSEventReceiveRunLoopMode 接收系統(tǒng)事件的內(nèi)部Mode,通常由系統(tǒng)自動(dòng)管理。
- kCFRunLoopCommonMode 一個(gè)類(lèi)似于占位的Mode,并不是一個(gè)真正的Mode。
CFRunLoopSourceRef:事件源、事件、輸入等都屬于事件源,它有兩個(gè)分類(lèi):
- Source0 非基于Port的事件,用戶觸發(fā)的事件,例如點(diǎn)擊事件等。
- Source1 基于Port的事件,他用于系統(tǒng)內(nèi)部與線程之間交互。
CFRunLoopTimerRef:定時(shí)器事件
- NSTimer
- 如果將NSTimer添加到子線程中,需要先創(chuàng)建一個(gè)RunLoop,然后再啟動(dòng)RunLoop。
- NSTimer受到RunLoop的影響,一般會(huì)有一些輕微的誤差,所以對(duì)于精密計(jì)時(shí),GCD定時(shí)器較為精準(zhǔn)。
- GCD定時(shí)器:精確到納秒,較為精準(zhǔn)。
- GCD定時(shí)器的創(chuàng)建步驟:創(chuàng)建定時(shí)器 -> 設(shè)置定時(shí)器 -> 設(shè)置定時(shí)器的回調(diào)方法 -> 恢復(fù)定時(shí)器。
- GCD定時(shí)器一定要添加一個(gè)強(qiáng)引用,否則會(huì)被立即釋放。
CFRunLoopObserverRef:觀察者
- 觀察者可以觀察到RunLoop不同的運(yùn)行狀態(tài)
- 通過(guò)判斷RunLoop的運(yùn)行狀態(tài),可以執(zhí)行一些操作。