OC底層知識(十) : RunLoop

一、Runloop的簡單介紹

Runloop 是在程序運(yùn)行過程中循環(huán)做一些事情。比如應(yīng)用在:定時器(NSTimer)、PerformSelector;GCD Async Main Queue;事件響應(yīng)、手勢識別、界面刷新、網(wǎng)絡(luò)請求、AutoreleasePool

  • RunLoop的基本作用:保持程序的持續(xù)運(yùn)行;處理App中的各種事件(如觸摸事件、定時器事件等);節(jié)省CPU資源,提高程序性能:該做事時做事,該休息時休息
二、RunLoop對象的獲取
  • 2.1、iOS中有2套API來訪問和使用RunLoop

    • Foundation:NSRunLoop
    • Core Foundation:CFRunLoopRef
  • 2.2、NSRunLoop和CFRunLoopRef都代表著RunLoop對象

    NSRunLoop是基于CFRunLoopRef的一層OC包裝

    CFRunLoopRef是開源的

  • 2.3、RunLoop與線程

    • 每條線程都有唯一的一個與之對應(yīng)的RunLoop對象
    • RunLoop保存在一個全局的Dictionary里,線程作為key,RunLoop作為value
    • 線程剛創(chuàng)建時并沒有RunLoop對象,RunLoop會在第一次獲取它時創(chuàng)建
    • RunLoop會在線程結(jié)束時銷毀
    • 主線程的RunLoop已經(jīng)自動獲?。▌?chuàng)建),子線程默認(rèn)沒有開啟RunLoop
  • 2.4、獲取RunLoop對象

    • OC(Foundation)獲取RunLoop對象

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

      CFRunLoopGetCurrent(); // 獲得當(dāng)前線程的RunLoop對象
      CFRunLoopGetMain(); // 獲得主線程的RunLoop對象
      
三、RunLoop相關(guān)的類

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

struct __CFRunLoop {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;                 /* locked for accessing mode list */
    __CFPort _wakeUpPort;                  // used for CFRunLoopWakeUp 
    Boolean _unused;
    volatile _per_run_data *_perRunData;   // reset for runs of the run loop
    pthread_t _pthread;
    uint32_t _winthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
    struct _block_item *_blocks_head;
    struct _block_item *_blocks_tail;
    CFAbsoluteTime _runTime;
    CFAbsoluteTime _sleepTime;
    CFTypeRef _counterpart;
};
  • 3.1、CFRunLoopModeRef

    • CFRunLoopModeRef代表RunLoop的運(yùn)行模式
    • 一個RunLoop包含若干個Mode,每個Mode又包含若干個Source0/Source1/Timer/Observer



    • RunLoop啟動時只能選擇其中一個Mode,作為currentMode
    • 如果需要切換Mode,只能退出當(dāng)前Loop,再重新選擇一個Mode進(jìn)入
      • 不同組的Source0/Source1/Timer/Observer能分隔開來,互不影響
    • 如果Mode里沒有任何Source0/Source1/Timer/Observer,RunLoop會立馬退出
    • CFRunLoopModeRef 2種Mode
      • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默認(rèn)Mode,通常主線程是在這個Mode下運(yùn)行
      • UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響
        WechatIMG100.jpeg
  • 3.2、RunLoop的運(yùn)行邏輯


    RunLoop的運(yùn)行邏輯
    • Source0
      觸摸事件處理
      performSelector:onThread:
    • Source1
      基于Port的線程間通信
      系統(tǒng)事件捕捉
    • Timers
      NSTimer
      performSelector:withObject:afterDelay:
    • Observers
      用于監(jiān)聽RunLoop的狀態(tài)
      UI刷新(BeforeWaiting)
      Autorelease pool(BeforeWaiting)
RunLoop的運(yùn)行邏輯
  • 3.3、RunLoop休眠的實(shí)現(xiàn)原理


    RunLoop休眠的實(shí)現(xiàn)原理
四、RunLoop在實(shí)際開中的應(yīng)用 下面練習(xí)的demo
  • 4.1、控制線程生命周期(線程?;睿?/p>

    • (1)OC核心代碼實(shí)現(xiàn)?;?: 看demo里面的類JKCPermenantThread

      self.innerThread = [[MJThread alloc] initWithBlock:^{
       
       // 線程?;? // 往RunLoop里面添加 Source\Timer\Observer
       [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
       
        while (weakSelf && !weakSelf.isStopped) {
           [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
      }];
      
    • (2)C核心代碼實(shí)現(xiàn)?;睿嚎磀emo里面的類ThreadCViewController

      self.innerThread = [[JKThread alloc] initWithBlock:^{
         NSLog(@"begin----");
       
         // 創(chuàng)建上下文(要初始化一下結(jié)構(gòu)體)
         CFRunLoopSourceContext context = {0};
       
         // 創(chuàng)建source
         CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
       
         // 往Runloop中添加source
         CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
       
         // 銷毀source
         CFRelease(source);
       
         // 啟動
         CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, false);
       
         //            while (weakSelf && !weakSelf.isStopped) {
         //                // 第3個參數(shù):returnAfterSourceHandled,設(shè)置為true,代表執(zhí)行完source后就會退出當(dāng)前l(fā)oop
         //                CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
         //            }
       
         NSLog(@"end----");
       }];
      
  • 4.2、解決NSTimer在滑動時停止工作的問題(我在做一個cell上動畫的時候用了NSRunLoop來防止tableview滑動的時候cell上的動畫暫停)

    NSTimer  *timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(clickTimeIndexPath) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    /*
      UITrackingRunLoopMode和NSDefaultRunLoopMode是真正存在的模式
      [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
      [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
      NSRunLoopCommonModes:n并不是一個真的模式,它只是一個標(biāo)記
      timer 能在 _commandModes 數(shù)組中存放的模式下工作
      [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
     */
    
  • 4.3、監(jiān)控應(yīng)用卡頓(看底層七)

  • 4.4、性能優(yōu)化(看底層七)

五、RunLoop的幾個面試題
  • 5.1、講講 RunLoop,項(xiàng)目中有用到嗎?(你可以回答里面的任意一個)
    答:我用到了:解決NSTimer在滑動時停止工作的問題(我在做一個cell上動畫的時候用了NSRunLoop來防止tableview滑動的時候cell上的動畫暫停)

  • 5.2、runloop內(nèi)部實(shí)現(xiàn)邏輯?
    答:看上面的 3.2、RunLoop的運(yùn)行邏輯

  • 5.3、runloop和線程的關(guān)系?
    答:看上面的 2.3、RunLoop與線程

  • 5.4、timer 與 runloop 的關(guān)系?
    答: timer 是運(yùn)行在runloop里面的,runloop控制 timer什么時候執(zhí)行

  • 5.5、程序中添加每3秒響應(yīng)一次的NSTimer,當(dāng)拖動tableview時timer可能無法響應(yīng)要怎么解決?
    答:看上面的4.2,也就是要添加 NSRunLoopCommonModes標(biāo)記

  • 5.6、runloop 是怎么響應(yīng)用戶操作的, 具體流程是什么樣的?
    答: 由 source1捕獲觸摸或者響應(yīng)事件,再由 source0去處理觸摸或者響應(yīng)事件

  • 5.7、說說runLoop的幾種狀態(tài)


    runLoop的幾種狀態(tài)
  • 5.8、runloop的mode作用是什么?
    答:runloop的mode 常用的有兩種mode: NSDefaultRunLoopModeUITrackingRunLoopMode,在某一種mode下執(zhí)行自己的source0、source1、timer,不同mode下互不影響,分工明確,使用起來更靈活、流暢。

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

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