runloop

NSRunLoop:
OSX/iOS 系統(tǒng)中,提供了兩個(gè)這樣的對象:NSRunLoop 和 CFRunLoopRef。
CFRunLoopRef 是在 CoreFoundation 框架內(nèi)的,它提供了純 C 函數(shù)的 API,所有這些 API 都是線程安全的。
NSRunLoop 是基于 CFRunLoopRef 的封裝,提供了面向?qū)ο蟮?API,但是這些 API 不是線程安全的。
NSRunLoop 與線程的關(guān)系:
其實(shí)runLoop就是一個(gè)do … while()函數(shù),每個(gè)runLoop對應(yīng)一個(gè)線程他們是一一對應(yīng)的關(guān)系,關(guān)系保存在一個(gè)全局的Dictionary里邊,線程剛創(chuàng)建時(shí)沒有RunLoop,如果不主動獲取,是不會有的,RunLoop的創(chuàng)建發(fā)生在第一次獲取時(shí),RunLoop的銷毀發(fā)生在線程結(jié)束,只能在一個(gè)線程的內(nèi)部獲取它的RunLoop(主線程除外)主線程默認(rèn)有個(gè)RunLoop.
Thread包含一個(gè)CFRunLoop,一個(gè)CFRunLoop包含一種CFRunLoopMode,mode包含CFRunLoopSource,CFRunLoopTimer和CFRunLoopObserver。
Runloop的寄生于線程:一個(gè)線程只能有唯一對應(yīng)的runloop;但這個(gè)根runloop里可以嵌套子runloops;
自動釋放池寄生于Runloop:程序啟動后,主線程注冊了兩個(gè)Observer監(jiān)聽runloop的進(jìn)出與睡覺。一個(gè)最高優(yōu)先級OB監(jiān)測Entry狀態(tài);一個(gè)最低優(yōu)先級OB監(jiān)聽BeforeWaiting狀態(tài)和Exit狀態(tài)。
線程(創(chuàng)建)-->runloop將進(jìn)入-->最高優(yōu)先級OB創(chuàng)建釋放池-->runloop將睡-->最低優(yōu)先級OB銷毀舊池創(chuàng)建新池-->runloop將退出-->最低優(yōu)先級OB銷毀新池-->線程(銷毀)
RunLoop只能運(yùn)行在一種mode下,如果要換mode當(dāng)前的loop也需要停下重啟成新的。利用這個(gè)機(jī)制,ScrollView過程中NSDefaultRunLoopMode的mode會切換UITrackingRunLoopMode來保證ScrollView的流暢滑動不受只能在NSDefaultRunLoopMode時(shí)處理的事件影響滑動。同時(shí)mode還是可定制的。
NSDefaultRunLoopMode:默認(rèn),空閑狀態(tài)
UITrackingRunLoopMode:ScrollView滑動時(shí)
UIInitializationRunLoopMode:啟動時(shí)
NSRunLoopCommonModes:Mode集合 Timer計(jì)時(shí)會被scrollView的滑動影響的問題可以通過將timer添加到NSRunLoopCommonModes來解決

//然后再添加到NSRunLoopCommonModes里  
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0  
    target:self  
    selector:@selector(timerTick:)  
    userInfo:nil  
    repeats:YES];  
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
/// 全局的Dictionary,key 是 pthread_t, value 是 CFRunLoopRef  
static CFMutableDictionaryRef loopsDic;  
/// 訪問 loopsDic 時(shí)的鎖  
static CFSpinLock_t loopsLock;  
  
/// 獲取一個(gè) pthread 對應(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);  
        /// 注冊一個(gè)回調(diào),當(dāng)線程銷毀時(shí),順便也銷毀其對應(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());  
}  

NSTimer和performSEL方法實(shí)際上是對CFRunloopTimerRef的封裝;runloop啟動時(shí)設(shè)置的最大超時(shí)時(shí)間實(shí)際上是GCD的dispatch_source_t類型。
數(shù)據(jù)結(jié)構(gòu):

// Timer:interval:(鬧鐘間隔), tolerance:(延期時(shí)間容忍度),callout(回調(diào)函數(shù))CFRunLoopTimer {firing =..., interval = ...,tolerance = ...,next fire date = ...,callout = ...}

創(chuàng)建與生效;
//NSTimer: // 創(chuàng)建一個(gè)定時(shí)器(需要手動加到runloop的mode中) + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo; // 默認(rèn)已經(jīng)添加到主線程的runLoop的DefaultMode中  + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;// performSEL方法// 內(nèi)部會創(chuàng)建一個(gè)Timer到當(dāng)前線程的runloop中(如果當(dāng)前線程沒runloop則方法無效;performSelector:onThread: 方法放到指定線程runloop中)- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay

相關(guān)類型(GCD的timer與CADisplayLink)
GCD的timer:dispatch_source_t 類型,可以精確的參數(shù),不用以來runloop和mode,性能消耗更小。

dispatch_source_set_timer(dispatch_source_t source, // 定時(shí)器對象 dispatch_time_t start, // 定時(shí)器開始執(zhí)行的時(shí)間 uint64_t interval, // 定時(shí)器的間隔時(shí)間 uint64_t leeway // 定時(shí)器的精度 );
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Run loop 剖析:Runloop 接收的輸入事件來自兩種不同的源:輸入源(intput source)和定時(shí)...
    Mitchell閱讀 12,642評論 17 111
  • 一、什么是runloop 字面意思是“消息循環(huán)、運(yùn)行循環(huán)”。它不是線程,但它和線程息息相關(guān)。一般來講,一個(gè)線程一次...
    WeiHing閱讀 8,306評論 11 111
  • 前言 最近離職了,可以盡情熬夜寫點(diǎn)總結(jié),不用擔(dān)心第二天上班爽并蛋疼著,這篇的主角 RunLoop 一座大山,涵蓋的...
    zerocc2014閱讀 12,549評論 13 67
  • ??昨天找一個(gè)高中同學(xué)聊了一會天,說了說雙方最近的狀態(tài)。目前他進(jìn)了一家類似外企的企業(yè),工資也還算可以,可是每天的生...
    張中華閱讀 185評論 3 0

友情鏈接更多精彩內(nèi)容