RunLoop 系列文章
深入淺出 RunLoop(一):初識
深入淺出 RunLoop(二):數(shù)據(jù)結(jié)構(gòu)
深入淺出 RunLoop(三):事件循環(huán)機(jī)制
深入淺出 RunLoop(四):RunLoop 與線程
深入淺出 RunLoop(五):RunLoop 與 NSTimer
iOS - 聊聊 autorelease 和 @autoreleasepool:RunLoop 與 @autoreleasepool
目錄
- CFRunLoopRef
- CFRunLoopModeRef
RunLoop 的常見模式
CFRunLoopModeRef 這樣設(shè)計有什么好處畜普?Runloop為什么會有多個 Mode游昼?- CFRunLoopSourceRef
- CFRunLoopTimerRef
- CFRunLoopObserverRef
CFRunLoopRef
RunLoop
對象的底層就是一個CFRunLoopRef
結(jié)構(gòu)體矢棚,它里面存儲著:
- _pthread:
RunLoop
與線程是一一對應(yīng)關(guān)系 - _commonModes:存儲著 NSString 對象的集合(Mode 的名稱)
- _commonModeItems:存儲著被標(biāo)記為通用模式的
Source0
/Source1
/Timer
/Observer
- _currentMode:
RunLoop
當(dāng)前的運行模式 - _modes:存儲著
RunLoop
所有的 Mode(CFRunLoopModeRef
)模式
// CFRunLoop.h
typedef struct __CFRunLoop * CFRunLoopRef;
// CFRunLoop.c
struct __CFRunLoop {
pthread_t _pthread; // 與線程一一對應(yīng)
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
...
};
CFRunLoopModeRef
-
CFRunLoopModeRef
代表RunLoop
的運行模式; - 一個
RunLoop
包含若干個 Mode,每個 Mode 又包含若干個Source0
/Source1
/Timer
/Observer
雀彼; -
RunLoop
啟動時只能選擇其中一個 Mode县踢,作為 currentMode; - 如果需要切換 Mode悼瓮,只能退出當(dāng)前 Loop戈毒,再重新選擇一個 Mode 進(jìn)入,切換模式不會導(dǎo)致程序退出横堡;
- 不同 Mode 中的
Source0
/Source1
/Timer
/Observer
能分隔開來埋市,互不影響; - 如果 Mode 里沒有任何
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
...
};
RunLoop 的常見模式
ModeName | 描述 |
---|---|
NSDefaultRunLoopMode / KCFRunLoopDefaultMode | 默認(rèn)模式 |
UITrackingRunLoopMode | 界面追蹤模式胸蛛,用于 ScrollView 追蹤觸摸滑動污茵,保證界面滑動時不受其他 Mode 影響; |
NSRunLoopCommonModes / KCFRunLoopCommonModes | 通用模式(默認(rèn)包含 KCFRunLoopDefaultMode 和 UITrackingRunLoopMode) 該模式不是實際存在的一種模式葬项,它只是一個特殊的標(biāo)記省咨,是同步 Source0 /Source1 /Timer /Observer 到多個 Mode 中的技術(shù)方案。被標(biāo)記為通用模式的Source0 /Source1 /Timer /Observer 都會存放到 _commonModeItems 集合中玷室,會同步這些Source0 /Source1 /Timer /Observer 到多個 Mode 中零蓉。 |
備注:
NSDefaultRunLoopMode
和NSRunLoopCommonModes
屬于Foundation
框架;KCFRunLoopDefaultMode
和KCFRunLoopCommonModes
屬于Core Foundation
框架穷缤;- 前者是對后者的封裝敌蜂,作用相同。
CFRunLoopModeRef 這樣設(shè)計有什么好處津肛?Runloop為什么會有多個 Mode章喉?
- Mode 做到了屏蔽的效果,當(dāng)
RunLoop
運行在 Mode1 下面的時候身坐,是處理不了 Mode2 的事件的秸脱; - 比如
NSDefaultRunLoopMode
默認(rèn)模式和UITrackingRunLoopMode
滾動模式,滾動屏幕的時候就會切換到滾動模式部蛇,就不用去處理默認(rèn)模式下的事件了摊唇,保證了 UITableView 等的滾動順暢。
CFRunLoopSourceRef
- 在
RunLoop
中有兩個很重要的概念涯鲁,一個是上面提到的模式
巷查,還有一個就是事件源
有序。事件源
分為輸入源(Input Sources)
和定時器源(Timer Sources)
兩種; -
輸入源(Input Sources)
又分為Source0
和Source1
兩種岛请,以下__CFRunLoopSource
中的共用體union
中的version0
和version1
就分別對應(yīng)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 的區(qū)別:
Input Sources | 區(qū)別 |
---|---|
Source0 | 需要手動喚醒線程:添加Source0 到RunLoop 并不會主動喚醒線程,需要手動喚醒)① 觸摸事件處理 ② performSelector:onThread:
|
Source1 | 具備喚醒線程的能力 ① 基于 Port 的線程間通信 ② 系統(tǒng)事件捕捉:系統(tǒng)事件捕捉是由 Source1 來處理崇败,然后再交給Source0 處理 |
CFRunLoopTimerRef
-
CFRunloopTimer
和NSTimer
是 toll-free bridged 的盅称,可以相互轉(zhuǎn)換; -
performSelector:withObject:afterDelay:
方法會創(chuàng)建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 回調(diào)入口 */
CFRunLoopTimerContext _context; /* immutable, except invalidation */
};
CFRunLoopObserverRef
作用
-
CFRunLoopObserverRef
用來監(jiān)聽RunLoop
的 6 種活動狀態(tài)
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 即將進(jìn)入 RunLoop
kCFRunLoopBeforeTimers = (1UL << 1), // 即將處理 Timers
kCFRunLoopBeforeSources = (1UL << 2), // 即將處理 Sources
kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進(jìn)入休眠
kCFRunLoopAfterWaiting = (1UL << 6), // 剛從休眠中喚醒
kCFRunLoopExit = (1UL << 7), // 即將退出 RunLoop
kCFRunLoopAllActivities = 0x0FFFFFFFU // 表示以上所有狀態(tài)
};
- UI 刷新(BeforeWaiting)
- Autorelease pool(BeforeWaiting)
定義
// 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 監(jiān)聽的活動狀態(tài) */
CFIndex _order; /* immutable */
CFRunLoopObserverCallBack _callout; /* immutable 回調(diào)入口 */
CFRunLoopObserverContext _context; /* immutable, except invalidation */
};
CFRunLoopObserverRef
中的_activities
用來保存RunLoop
的活動狀態(tài)缩膝。當(dāng)RunLoop
的狀態(tài)發(fā)生改變時,通過回調(diào)_callout
通知所有監(jiān)聽這個狀態(tài)的Observer
咧擂。