RunLoop備忘

小星星_ios發表於2020-03-23

什麼是 RunLoop

  • 應用範疇

    • 定時器、PerformSelector
    • GCD Async Main Queue
    • 事件響應、手勢識別、介面重新整理
    • 網路請求
    • AutoreleasePool
  • RunLoop的基本作用

    • 保持程式的持續執行
    • 處理 App 中的各種事件
    • 節省CPU資源,提高程式效能:該做事時做事,該休息時休息

RunLoop物件

NSRunLoop 是基於 CFRunLoopRef 的一層 OC 包裝

RunLoop與執行緒

  • 每條執行緒都有唯一的一個與之對應的 RunLoop物件
  • RunLoop 儲存在一個全域性的 Dictionary裡,執行緒作為 key,RunLoop 作為 value
  • 執行緒剛建立時並沒有 RunLoop物件,RunLoop 會在第一次獲取它時建立
  • RunLoop會線上程結束時銷燬
  • 主執行緒 RunLoop 自動獲取,子執行緒預設沒有開啟 RunLoop(這個就是你在子執行緒只開啟runloop他仍然會退出的原因)

RunLoop相關的類

  • CFRunLoopRef
  • CFRunLoopModeRef
  • CFRunLoopSourceRef
  • CFRunLoopTimerRef
  • CFRunLoopObserverRef
struct __CFRunLoop {
    pthread_t _pthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
}

struct __CFRunLoopMode {
    CFStringRef _name;
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
}
複製程式碼

CFRunLoopModeRef

  • CFRunLoopModeRef 代表 RunLoop 的執行模式
  • 一個 RunLoop 包含若干個 Mode,每個 Mode 又包含若干個 Source0/Source1/Timer/Observer
  • RunLoop啟動時只能選擇其中一個 Mode,作為 currentMode
  • 如果需要切換Mode,只能退出當前 Loop,再重新選擇一個 Mode 進入,不同組的Source0/Source1/Timer/Observer能分隔開,互不影響
  • 如果 Mode 裡沒有任何 Source0/Source1/Timer/Observer,RunLoop會立馬退出
  • 常見的兩種 Mode
    • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App預設的Mode,通常主執行緒是在這個Mode下執行
    • UITrackingRunLoopMode:介面跟蹤 Mode,用於 ScrollView 追蹤觸控滑動,保證介面滑動時不受其他 Mode影響

RunLoop的執行邏輯

  • Source0

    • 觸控事件處理
    • performSelector:onThread:
  • Source1

    • 基於 Port 的執行緒間通訊
    • 系統事件的捕捉
  • Timers

    • NSTimer
    • performSelector:withObject:afterDelay:
  • Observers

    • 用於監聽 RunLoop 的狀態
    • UI重新整理(BeforeWaiting)
    • AutoreleasePool(BeforeWaiting)

休眠的細節

使用者態呼叫mach_msg(),就會切換到核心態去真正執行mach_msg(),讓執行緒等待訊息(沒有訊息讓執行緒休眠,有訊息就喚醒執行緒)

執行緒保活

[[NSRunLoop currentRunLoop] run]是無法停止的,它專門用於開啟一個永不銷燬的執行緒(NSRunLoop)
複製程式碼

RunLoop內部實現的邏輯

RunLoop備忘