深刻淺出 RunLoop(一):初識
深刻淺出 RunLoop(二):數據結構
深刻淺出 RunLoop(三):事件循環機制
深刻淺出 RunLoop(四):RunLoop 與線程
深刻淺出 RunLoop(五):RunLoop 與 NSTimer
iOS - 聊聊 autorelease 和 @autoreleasepool:RunLoop 與 @autoreleasepoolmarkdown
RunLoop
對象的底層就是一個CFRunLoopRef
結構體,它裏面存儲着:數據結構
RunLoop
與線程是一一對應關係Source0
/Source1
/Timer
/Observer
RunLoop
當前的運行模式RunLoop
全部的 Mode(CFRunLoopModeRef
)模式// CFRunLoop.h typedef struct __CFRunLoop * CFRunLoopRef; // CFRunLoop.c struct __CFRunLoop { pthread_t _pthread; // 與線程一一對應 CFMutableSetRef _commonModes; CFMutableSetRef _commonModeItems; CFRunLoopModeRef _currentMode; CFMutableSetRef _modes; ... }; 複製代碼
CFRunLoopModeRef
表明RunLoop
的運行模式;RunLoop
包含若干個 Mode,每一個 Mode 又包含若干個Source0
/Source1
/Timer
/Observer
;RunLoop
啓動時只能選擇其中一個 Mode,做爲 currentMode;Source0
/Source1
/Timer
/Observer
能分隔開來,互不影響;Source0
/Source1
/Timer
/Observer
,RunLoop
會立馬退出。// CFRunLoop.h typedef struct __CFRunLoopMode *CFRunLoopModeRef; // CFRunLoop.c struct __CFRunLoopMode { CFStringRef _name; // mode 類型,如:NSDefaultRunLoopMode CFMutableSetRef _sources0; // CFRunLoopSourceRef CFMutableSetRef _sources1; // CFRunLoopSourceRef CFMutableArrayRef _observers; // CFRunLoopObserverRef CFMutableArrayRef _timers; // CFRunLoopTimerRef ... }; 複製代碼
ModeName | 描述 |
---|---|
NSDefaultRunLoopMode / KCFRunLoopDefaultMode | 默認模式 |
UITrackingRunLoopMode | 界面追蹤模式,用於 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其餘 Mode 影響; |
NSRunLoopCommonModes / KCFRunLoopCommonModes | 通用模式(默認包含 KCFRunLoopDefaultMode 和 UITrackingRunLoopMode) 該模式不是實際存在的一種模式,它只是一個特殊的標記,是同步 Source0 /Source1 /Timer /Observer 到多個 Mode 中的技術方案。被標記爲通用模式的Source0 /Source1 /Timer /Observer 都會存放到 _commonModeItems 集合中,會同步這些Source0 /Source1 /Timer /Observer 到多個 Mode 中。 |
備註:框架
NSDefaultRunLoopMode
和NSRunLoopCommonModes
屬於Foundation
框架;KCFRunLoopDefaultMode
和KCFRunLoopCommonModes
屬於Core Foundation
框架;- 前者是對後者的封裝,做用相同。
RunLoop
運行在 Mode1 下面的時候,是處理不了 Mode2 的事件的;NSDefaultRunLoopMode
默認模式和UITrackingRunLoopMode
滾動模式,滾動屏幕的時候就會切換到滾動模式,就不用去處理默認模式下的事件了,保證了 UITableView 等的滾動順暢。RunLoop
中有兩個很重要的概念,一個是上面提到的模式
,還有一個就是事件源
。事件源
分爲輸入源(Input Sources)
和定時器源(Timer Sources)
兩種;輸入源(Input Sources)
又分爲Source0
和Source1
兩種,如下__CFRunLoopSource
中的共用體union
中的version0
和version1
就分別對應Source0
和Source1
。// CFRunLoop.h typedef struct __CFRunLoopSource * CFRunLoopSourceRef; // CFRunLoop.m struct __CFRunLoopSource { CFRuntimeBase _base; uint32_t _bits; pthread_mutex_t _lock; CFIndex _order; /* immutable */ CFMutableBagRef _runLoops; union { CFRunLoopSourceContext version0; /* immutable, except invalidation */ CFRunLoopSourceContext1 version1; /* immutable, except invalidation */ } _context; }; 複製代碼
Source0 和 Source1 的區別:oop
Input Sources | 區別 |
---|---|
Source0 | 須要手動喚醒線程:添加Source0 到RunLoop 並不會主動喚醒線程,須要手動喚醒)① 觸摸事件處理 ② performSelector:onThread: |
Source1 | 具有喚醒線程的能力 ① 基於 Port 的線程間通訊 ② 系統事件捕捉:系統事件捕捉是由 Source1 來處理,而後再交給Source0 處理 |
CFRunloopTimer
和NSTimer
是 toll-free bridged 的,能夠相互轉換;performSelector:withObject:afterDelay:
方法會建立timer
並添加到RunLoop
中。// CFRunLoop.h typedef struct CF_BRIDGED_MUTABLE_TYPE(NSTimer) __CFRunLoopTimer * CFRunLoopTimerRef; // CFRunLoop.c struct __CFRunLoopTimer { CFRuntimeBase _base; uint16_t _bits; pthread_mutex_t _lock; CFRunLoopRef _runLoop; // 添加該 timer 的 RunLoop CFMutableSetRef _rlModes; // 全部包含該 timer 的 modeName CFAbsoluteTime _nextFireDate; CFTimeInterval _interval; /* immutable 理想時間間隔 */ CFTimeInterval _tolerance; /* mutable 時間誤差 */ uint64_t _fireTSR; /* TSR units */ CFIndex _order; /* immutable */ CFRunLoopTimerCallBack _callout; /* immutable 回調入口 */ CFRunLoopTimerContext _context; /* immutable, except invalidation */ }; 複製代碼
做用post
CFRunLoopObserverRef
用來監聽RunLoop
的 6 種活動狀態/* Run Loop Observer Activities */ typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { kCFRunLoopEntry = (1UL << 0), // 即將進入 RunLoop kCFRunLoopBeforeTimers = (1UL << 1), // 即將處理 Timers kCFRunLoopBeforeSources = (1UL << 2), // 即將處理 Sources kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進入休眠 kCFRunLoopAfterWaiting = (1UL << 6), // 剛從休眠中喚醒 kCFRunLoopExit = (1UL << 7), // 即將退出 RunLoop kCFRunLoopAllActivities = 0x0FFFFFFFU // 表示以上全部狀態 }; 複製代碼
定義ui
// CFRunLoop.h typedef struct __CFRunLoopObserver * CFRunLoopObserverRef; // CFRunLoop.c struct __CFRunLoopObserver { CFRuntimeBase _base; pthread_mutex_t _lock; CFRunLoopRef _runLoop; // 添加該 observer 的 RunLoop CFIndex _rlCount; CFOptionFlags _activities; /* immutable 監聽的活動狀態 */ CFIndex _order; /* immutable */ CFRunLoopObserverCallBack _callout; /* immutable 回調入口 */ CFRunLoopObserverContext _context; /* immutable, except invalidation */ }; 複製代碼
CFRunLoopObserverRef
中的_activities
用來保存RunLoop
的活動狀態。當RunLoop
的狀態發生改變時,經過回調_callout
通知全部監聽這個狀態的Observer
。spa