RunLoop概述
一般來講茉盏,一個線程一次只能執(zhí)行一個任務(wù)儡循,執(zhí)行完成后線程就會退出混滔。如果我們需要一個機(jī)制洒疚,讓線程能隨時處理事件但并不退出,通常的代碼邏輯是這樣的:
Event loop
RunLoop和Thread
-
RunLoop和線程的關(guān)系:
一個RunLoop對應(yīng)著一條唯一的線程
-
RunLoop的創(chuàng)建:
MainThread上的RunLoop默認(rèn)是創(chuàng)建好并啟動的遍坟,其它Thread中的RunLoop默認(rèn)是沒有創(chuàng)建RunLoop
- RunLoop的生命周期:
在第一次獲取時創(chuàng)建拳亿,在線程結(jié)束時銷毀。除了MainThread外愿伴,其它Thread首次獲取該Thread的RunLoop時才被創(chuàng)建肺魁,代碼流程見下面
// 全局的 Dictionary ,key 是 pthread_t 隔节, value 是 CFRunLoopRef
static CFMutableDictionaryRef loopsDic;
// 訪問 loopsDic 時的線程鎖
static CFSpinLock_t loopsLock;
// 獲取一個 pthread 對應(yīng)的 RunLoop
CFRunLoopRef _CFRunLoopGet(pthread_t thread) {
OSSpinLockLock(&loopsLock);
if (!loopsDic) {
// 第一次進(jìn)入時鹅经,初始化全局 Dic ,并先為主線程創(chuàng)建一個RunLoop
loopsDic = CFDictionaryCreateMutable();
CFRunLoopRef mainLoop = _CFRunLoopCreate();
CFDictionarySetValue(loopsDic, pthread_main_thread_np(), mainLoop);
}
// 直接從 Dictionary 里獲取 thread
CFRunLoopRef loop = CFDictionaryGetValue(loopsDis, thread);
if (!loop) {
// 如果取不到怎诫,創(chuàng)建一個
loop = _CFRunLoopCreate();
CFDictionarySetValue(loopsDic, thread, loop);
// 注冊一個回調(diào)瘾晃,當(dāng)線程銷毀時,順便也銷毀其對應(yīng)的 RunLoop
_CFSetTSD(..., thread, loop, __CFFinalizeRunLoop);
}
OSSpinLockUnLock(&loopsLock);
return loop;
}
從上面的代碼可以看出幻妓,線程和RunLoop之間是一一對應(yīng)的蹦误,其關(guān)系是保存在一個全局的Dictionary里。線程剛創(chuàng)建時并沒有RunLoop,如果你不主動獲取强胰,那它一直都不會被創(chuàng)建舱沧。RunLoop的創(chuàng)建是發(fā)生在第一次獲取時,RunLoop的銷毀是發(fā)生在線程結(jié)束時偶洋。只能在一個線程的內(nèi)部獲取其RunLoop(MainThread除外)熟吏。
注意:
- 開一個子線程創(chuàng)建RunLoop,不是通過alloc init方法創(chuàng)建玄窝,而是直接通過調(diào)用currentRunLoop方法來創(chuàng)建牵寺,它本身是一個懶加載的。
- RunLoop對象是利用字典來進(jìn)行存儲的恩脂,而且key是對應(yīng)的Thread帽氓,value為該Thread對應(yīng)的RunLoop
- CFRunLoopRef源碼可以在CoreFoundation源碼中進(jìn)行了解