RunLoop

RunLoop

RunLoop就是運(yùn)行循環(huán),處理app中的各種事件(比如觸摸事件,定時(shí)器事件,Selector事件)
一個(gè)線程對(duì)應(yīng)一個(gè)RunLoop,主線程的RunLoop已經(jīng)自動(dòng)創(chuàng)建好了,子線程的RunLoop需要主動(dòng)創(chuàng)建,RunLoop在第一次獲取時(shí)創(chuàng)建,線程結(jié)束時(shí)銷毀

RunLoop的獲得

  • Foundation
    • [NSRunLoop currentRunLoop]; // 獲得當(dāng)前線程的RunLoop對(duì)象
    • [NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對(duì)象
  • Core Foundation
    • CFRunLoopGetCurrent(); // 獲得當(dāng)前線程的RunLoop對(duì)象
    • CFRunLoopGetMain(); // 獲得主線程的RunLoop對(duì)象

RunLoop相關(guān)類

  • Core Foundation中關(guān)于RunLoop的5個(gè)類
    • CFRunLoopRef
    • CFRunLoopModeRef
    • CFRunLoopSourceRef
    • CFRunLoopTimerRef
    • CFRunLoopObserverRef

RunLoop的組成

  • Mode
    • Timer
    • source
    • Observer

Mode

Mode代表RunLoop的運(yùn)行模式。每次RunLoop職能指定一個(gè)Mode運(yùn)行。切換Mode職能退出Loop,再重新指定一個(gè)Mode進(jìn)入。
一個(gè) RunLoop 包含若干個(gè) Mode,每個(gè)Mode又包含若干個(gè)Source/Timer/Observer

系統(tǒng)默認(rèn)的5個(gè)Mode

  • NSDefaultRunLoopMode:App的默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行

  • UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動(dòng),保證界面滑動(dòng)時(shí)不受其他 Mode 影響

  • UIInitializationRunLoopMode: 在剛啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode,啟動(dòng)完成后就不再使用

  • GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到

  • NSRunLoopCommonModes: 這是一個(gè)占位用的Mode,不是一種真正的Mode(既執(zhí)行Default中的事件也執(zhí)行track中的事件)

Timer

CFRunLoopTimerRef是基于時(shí)間的觸發(fā)器

CFRunLoopTimerRef基本上說的就是NSTimer,它受RunLoop的Mode影響

GCD的定時(shí)器不受RunLoop的Mode影響

- (void)timer
{
    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
    // 定時(shí)器只運(yùn)行在NSDefaultRunLoopMode下,一旦RunLoop進(jìn)入其他模式,這個(gè)定時(shí)器就不會(huì)工作(比如textField的拖動(dòng))
    //    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    
    // 定時(shí)器只運(yùn)行在UITrackingRunLoopMode下,一旦RunLoop進(jìn)入其他模式,這個(gè)定時(shí)器就不會(huì)工作
    //    [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
    
    // 定時(shí)器會(huì)跑在標(biāo)記為common modes的模式下
    // 標(biāo)記為common modes的模式:UITrackingRunLoopMode和NSDefaultRunLoopMode
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

- (void)timer2
{
    // 調(diào)用了scheduledTimer返回的定時(shí)器,已經(jīng)自動(dòng)被添加到當(dāng)前runLoop中,而且是NSDefaultRunLoopMode
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
    
    // 修改模式
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

- (void)run
{
    NSLog(@"----run");
}

Source

  • CFRunLoopSourceRef是事件源(輸入源)

  • 按照官方文檔,Source的分類

    • Port-Based Sources (跟其他線程交互,或通過內(nèi)核發(fā)送的消息)
    • Custom Input Sources (自動(dòng)以輸入源,幾乎不用)
    • Cocoa Perform Selector Sources (比如performSelecter等方法)
  • 按照函數(shù)調(diào)用棧,Source的分類

    • Source0:非基于Port的
    • Source1:基于Port的,通過內(nèi)核和其他線程通信,接收、分發(fā)系統(tǒng)事件

事件的傳入都是先傳入Source1。然后再由Source1分發(fā)至source0進(jìn)行處理。所以在函數(shù)調(diào)用棧中往往只看到Source0。

Obersver

CFRunLoopObserverRef是觀察者,能夠監(jiān)聽RunLoop的狀態(tài)改變

  • 可以監(jiān)聽的時(shí)間點(diǎn)
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0), // 1
    kCFRunLoopBeforeTimers = (1UL << 1), // 2
    kCFRunLoopBeforeSources = (1UL << 2), // 4
    kCFRunLoopBeforeWaiting = (1UL << 5), // 32
    kCFRunLoopAfterWaiting = (1UL << 6), // 64
    kCFRunLoopExit = (1UL << 7), // 128
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};
  • 添加Observer
- (void)observer
{
    // 創(chuàng)建observer
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        NSLog(@"----監(jiān)聽到RunLoop狀態(tài)發(fā)生改變---%zd", activity);
    });

    // 添加觀察者:監(jiān)聽RunLoop的狀態(tài)
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    
    // 釋放Observer
    //凡是帶有Create、Copy、Retain等字眼的函數(shù),創(chuàng)建出來的對(duì)象,都需要在最后做一次release
    //比如CFRunLoopObserverCreate
    //release函數(shù):CFRelease(對(duì)象);
    
    CFRelease(observer);
}

RunLoop處理邏輯

  • 1:通知觀察者run loop已經(jīng)啟動(dòng)
  • 2:通知觀察者任何即將要開始的定時(shí)器
  • 3:通知觀察者任何即將啟動(dòng)的source0
  • 4:啟動(dòng)任何準(zhǔn)備好的source0
  • 5:如果接收到source1準(zhǔn)備好并處于等待狀態(tài),立即啟動(dòng),并進(jìn)入步驟9
  • 6:通知觀察者線程進(jìn)入休眠
  • 7:將線程置于休眠直到任何一下面的事件發(fā)生:
    • 某一事件到達(dá)source1
    • 定時(shí)器啟動(dòng)
    • runloop設(shè)置的時(shí)間超時(shí)
    • runloop被顯式喚醒
  • 8:通知觀察者線程將被喚醒
  • 9:處理未處理的事件
    • 如果用戶定義的定時(shí)器啟動(dòng),處理定時(shí)器事件并重啟runloop,進(jìn)入步驟2
    • 如果輸入源啟動(dòng),傳遞相應(yīng)的消息
    • 如果runloop被顯示喚醒而且時(shí)間還未超時(shí),重啟runloop,進(jìn)入步驟2
  • 10:通知觀察者runloop結(jié)束
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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