1、概念
RunLoop與線程關(guān)聯(lián)的,是一種事件處理環(huán),用來安排和協(xié)調(diào)到來的事件,目的就是讓其關(guān)聯(lián)的線程在有事件到達(dá)時(shí)時(shí)刻保持運(yùn)行狀態(tài),而當(dāng)沒有事件需要處理時(shí)進(jìn)入睡眠狀態(tài)從而節(jié)約資源,每一個(gè)線程都可以有一個(gè)RunLoop對象與之對應(yīng),并且是在第一次獲取它是系統(tǒng)自動(dòng)創(chuàng)建的,比如主線程關(guān)聯(lián)的RunLoop,我們都知道程序的入口函數(shù)是main函數(shù),下面是創(chuàng)建工程后Xcode自動(dòng)生成的main.m文件的main函數(shù)代碼:
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
該方法執(zhí)行體被autoreleasepool包圍,所以程序可以使用ARC來管理內(nèi)存,后面會(huì)講解RunLoop與autoreleasepool的關(guān)系,main函數(shù)直接返回了UIApplicationMain函數(shù),該函數(shù)內(nèi)部就會(huì)第一次獲取RunLoop對象,所以系統(tǒng)就會(huì)創(chuàng)建這樣一個(gè)RunLoop對象,因此在沒有滿足特定條件的時(shí)候該主線程不會(huì)退出,應(yīng)用就可以持續(xù)運(yùn)行而不會(huì)退出。
在官方文檔中使用下圖描述RunLoop模型:

從上圖可以看出一個(gè)線程會(huì)關(guān)聯(lián)一個(gè)RunLoop對象,RunLoop對象會(huì)一直循環(huán),直到超時(shí)或收到退出指令。在無限循環(huán)的過程中會(huì)一直處理到來的事件,右側(cè)將事件分為了兩類,一類是Input sources這部分包括基于端口的source1事件,開發(fā)者提交的各種source0事件,調(diào)用performSelector:onThread:方法事件,還有一類Timer sources這個(gè)就是常用的定時(shí)器事件,這些事件在程序運(yùn)行期間會(huì)不斷產(chǎn)生之后會(huì)由RunLoop對象檢測并負(fù)責(zé)處理相關(guān)事件。
2、RunLoop 源碼解析
RunLoop有兩個(gè)對象,NSRunLoop和CFRunLoopRef,區(qū)別在于由Core Foundation框架提供的CFRunLoopRef是純C語言編寫的,提供的也是C語言接口,這些接口都是線程安全的,由Foundation框架提供的NSRunLoop是面向?qū)ο蟮?,它是基?code>CFRunLoopRef的封裝,提供的都是面向?qū)ο蟮慕涌?,但這些接口不是線程安全的,Core Foudation框架是開源的,可以在這個(gè)地址下載:Core Foundation開源代碼,本文接下來的內(nèi)容主要是針對該開源代碼進(jìn)行講解。
首先,看一下在代碼中如何獲取RunLoop對象,在Foundation框架中的NSRunLoop類提供了如下兩個(gè)類屬性:
//獲取當(dāng)前線程關(guān)聯(lián)的RunLoop對象
@property (class, readonly, strong) NSRunLoop *currentRunLoop;
//獲取主線程關(guān)聯(lián)的RunLoop對象
@property (class, readonly, strong) NSRunLoop *mainRunLoop
對應(yīng)的Core Foundation里提供下面兩個(gè)函數(shù)來獲取RunLoop對象
//獲得當(dāng)前線程關(guān)聯(lián)的RunLoop對象
CFRunLoopGetCurrent();
// 獲得主線程關(guān)聯(lián)的RunLoop對象
CFRunLoopGetMain();
具體細(xì)節(jié)可以查閱這里:深入理解RunLoop