OC底層基礎(chǔ):RunLoop

查看oc文件底層結(jié)構(gòu)

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xxx.m

支持ARC、指定運行時系統(tǒng)版本

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-15.0.0 xxx.m

一、RunLoop基礎(chǔ)

1. RunLoop對象

  • iOS中有兩套API來訪問和使用RunLoop

    1. Foundation : NSRunLoop
    2. Core Foundation : CFRunLoopRef
  • RunLoopCFRunloopRef都代表著RunLoop對象

    1. NSRunloop是基于CFRunLoopRef的一層OC包裝
    2. CFRunLoopRef是開源的
  • Foundation

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

    1. CFRunLoopRefGetCurrent(); 獲得當(dāng)前線程的 RunLoop對象
    2. CFRunLoopRefGetMain(); 獲得主線程的RunLoop對象

注:https://opensource.apple.com/tarballs/CF/

  • 程序并不會馬上退出,而是保持運行狀態(tài)
  • RunLoop的基本作用
    1. 保持程序的持續(xù)運行
    2. 處理App中各種事件(如:觸摸事件、定時器事件等)
    3. 節(jié)省CPU資源,提高程序性能:該做事時做事,該休息時休息
    4. ……


      RunLoop的基本作用1.png

      RunLoop的基本作用2.png

2 . RunLoop與線程

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

3. RunLoop相關(guān)的類

  • Core Foundation中關(guān)于RunLoop的5個類
    1. CFRunLoopRef
    2. CFRunLoopModeRef
    3. CFRunLoopSourceRef
    4. CFRunLoopTimerRef
    5. CFRunLoopObserverRef
typedef struct __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop {
    pthread_t _pthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
};
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
    CFStringRef _name;
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
};
RunLoop相關(guān)的類.png
  • CFRunLoopModeRef

    1. CFRunLoopModeRef代表RunLoop的運行模式
    2. 一個RunLoop包含若干個Mode,每一個Mode又包含若干個sources0/sources1/Timer/observer
    3. RunLoop啟動時只能選擇其中一個Mode作為currentMode
    4. 如果需要切換Mode,只能退出當(dāng)前Loop,再重新選擇一個Mode進入
      • 不同組的sources0/sources1/Timer/observer能分隔開來,互不影響
    5. 如果Mode里沒有sources0/sources1/Timer/observer,RunLoop會立馬退出
    6. 常見的兩種Mode
      • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默認Mode,通常主線程是在這個Mode下運行
      • UITrackingRunLoopMode:界面跟蹤Mode,用于ScrollView追蹤觸摸滑動,保證界面滑動時不受其他Mode影響
  • CFRunLoopObserverRef

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0), //即將進入Loop
    kCFRunLoopBeforeTimers = (1UL << 1), // 即將處理Timer
    kCFRunLoopBeforeSources = (1UL << 2), // 即將處理Source
    kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進入休眠
    kCFRunLoopAfterWaiting = (1UL << 6), // 剛從休眠中喚醒
    kCFRunLoopExit = (1UL << 7), // 即將退出Loop
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

二、RunLoop的運行邏輯

  • Source0
    1. 觸摸事件處理
    2. performSelector:onThread:
  • Source1
    1. 基于Port的線程間通信
    2. 系統(tǒng)事件捕捉
  • Timers
    1. NSTimer
    2. performSelector:withObject:afterDelay:
  • Observers
    1. 用于監(jiān)聽RunLoop的狀態(tài)
    2. UI刷新(BeforeWaiting
    3. Autorelease poolBeforeWaiting
RunLoop的運行邏輯.png

三、RunLoop休眠的實現(xiàn)原理

  • 等待消息
    1. 沒有消息就讓線程休眠
    2. 有消息就喚醒線程


      RunLoop休眠的實現(xiàn)原理.png

四、RunLoop在實際的應(yīng)用

  • 控制線程生命周期(線程?;睿?/li>
  • 解決NSTimer在滑動時停止工作的問題
  • 監(jiān)控應(yīng)用卡頓
  • 性能優(yōu)化

注:可能涉及的面試題

  • 講講RunLoop,項目中有用到嗎
  • RunLoop內(nèi)部實現(xiàn)邏輯
  • RunLoop和線程的關(guān)系
  • timerRunLoop的關(guān)系
  • 程序中添加每3秒響應(yīng)一次的NSTimer,當(dāng)拖動tableViewtimer可能無法響應(yīng)要怎么解決
  • RunLoop是怎么響應(yīng)用戶操作的,具體流程是什么樣的
  • 說說RunLoop的幾種狀態(tài)
  • RunLoopmode作用是什么

上一篇:
OC底層基礎(chǔ):Block
下一篇:
OC底層基礎(chǔ):多線程GCD

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

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

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