首先逆害,iOS 開發(fā)中能遇到兩個(gè)線程對(duì)象: pthread_t 和 NSThread头镊。過去蘋果有份文檔標(biāo)明了 NSThread 只是 pthread_t 的封裝,但那份文檔已經(jīng)失效了魄幕,現(xiàn)在它們也有可能都是直接包裝自最底層的 mach thread相艇。蘋果并沒有提供這兩個(gè)對(duì)象相互轉(zhuǎn)換的接口,但不管怎么樣纯陨,可以肯定的是 pthread_t 和 NSThread 是一一對(duì)應(yīng)的坛芽。比如,你可以通過 pthread_main_thread_np()
或 [NSThread mainThread]
來獲取主線程翼抠;也可以通過 pthread_self()
或[NSThread currentThread]
來獲取當(dāng)前線程咙轩。CFRunLoop 是基于 pthread 來管理的。
蘋果不允許直接創(chuàng)建 RunLoop阴颖,它只提供了兩個(gè)自動(dòng)獲取的函數(shù):CFRunLoopGetMain()
和 CFRunLoopGetCurrent()
活喊。 這兩個(gè)函數(shù)內(nèi)部的邏輯大概是下面這樣:
/// 全局的Dictionary,key 是 pthread_t膘盖, value 是 CFRunLoopRef
static CFMutableDictionaryRef loopsDic;
/// 訪問 loopsDic 時(shí)的鎖
static CFSpinLock_t loopsLock;
/// 獲取一個(gè) pthread 對(duì)應(yīng)的 RunLoop胧弛。
CFRunLoopRef _CFRunLoopGet(pthread_t thread) {
OSSpinLockLock(&loopsLock);
if (!loopsDic) {
// 第一次進(jìn)入時(shí)尤误,初始化全局Dic侠畔,并先為主線程創(chuàng)建一個(gè) RunLoop。
loopsDic = CFDictionaryCreateMutable();
CFRunLoopRef mainLoop = _CFRunLoopCreate();
CFDictionarySetValue(loopsDic, pthread_main_thread_np(), mainLoop);
}
/// 直接從 Dictionary 里獲取损晤。
CFRunLoopRef loop = CFDictionaryGetValue(loopsDic, thread));
if (!loop) {
/// 取不到時(shí)软棺,創(chuàng)建一個(gè)
loop = _CFRunLoopCreate();
CFDictionarySetValue(loopsDic, thread, loop);
/// 注冊(cè)一個(gè)回調(diào),當(dāng)線程銷毀時(shí)尤勋,順便也銷毀其對(duì)應(yīng)的 RunLoop喘落。
_CFSetTSD(..., thread, loop, __CFFinalizeRunLoop);
}
OSSpinLockUnLock(&loopsLock);
return loop;
}
CFRunLoopRef CFRunLoopGetMain() {
return _CFRunLoopGet(pthread_main_thread_np());
}
CFRunLoopRef CFRunLoopGetCurrent() {
return _CFRunLoopGet(pthread_self());
}
從上面的代碼可以看出,線程和 RunLoop 之間是一一對(duì)應(yīng)的最冰,其關(guān)系是保存在一個(gè)全局的 Dictionary 里瘦棋。線程剛創(chuàng)建時(shí)并沒有 RunLoop,如果你不主動(dòng)獲取暖哨,那它一直都不會(huì)有赌朋。RunLoop 的創(chuàng)建是發(fā)生在第一次獲取時(shí),RunLoop 的銷毀是發(fā)生在線程結(jié)束時(shí)篇裁。你只能在一個(gè)線程的內(nèi)部獲取其 RunLoop(主線程除外)沛慢。
更多:iOS面試題合集