1.runloop源碼
2.對象介紹
接下來的對象介紹,可以借助這個(gè)圖理清對象間的關(guān)系
// 一個(gè)runloop對象
typedef struct __CFRunLoop * CFRunLoopRef;
// source
typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
// observer觀察者
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
// timer
typedef struct __CFRunLoopTimer * CFRunLoopTimerRef;
// mode
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
2.1. CFRunLoopRef
一個(gè)指向__CFRunLoop結(jié)構(gòu)體的指針
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;
CFTypeRef _counterpart;
};
從這個(gè)結(jié)構(gòu)體的內(nèi)容可以看出:
- 一個(gè)runloop對象主要包含modes沥曹、線程
- modes是一個(gè)可變集合被碗,里面存著mode藻肄,所以一個(gè)runloop對象可以包含多個(gè)mode
- 一個(gè) RunLoop 包含若干個(gè) Mode木柬,每個(gè) Mode 又包含若干個(gè) Source/Timer/Observer缰雇。(這三個(gè)的概念后面講)入偷。每次調(diào)用 RunLoop 的主函數(shù)時(shí),只能指定其中一個(gè) Mode寓涨,這個(gè)Mode被稱作 CurrentMode盯串。如果需要切換 Mode,只能退出 Loop戒良,再重新指定一個(gè) Mode 進(jìn)入体捏。這樣做主要是為了分隔開不同組的 Source/Timer/Observer,讓其互不影響糯崎。
2.2. CFRunLoopSourceRef
一個(gè)指向__CFRunLoopSource結(jié)構(gòu)體的指針
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;
};
結(jié)構(gòu)體有一個(gè)_runLoops(可變包對象)几缭,說明一個(gè)source可以添加到多個(gè)runloop中
CFRunLoopSourceContext version0
typedef struct {
CFIndex version;
void * info;
const void *(*retain)(const void *info);
void (*release)(const void *info);
CFStringRef (*copyDescription)(const void *info);
Boolean (*equal)(const void *info1, const void *info2);
CFHashCode (*hash)(const void *info);
void (*schedule)(void *info, CFRunLoopRef rl, CFStringRef mode);
void (*cancel)(void *info, CFRunLoopRef rl, CFStringRef mode);
void (*perform)(void *info);
} CFRunLoopSourceContext;
- CFRunLoopSourceContext1 version1
typedef struct {
CFIndex version;
void * info;
const void *(*retain)(const void *info);
void (*release)(const void *info);
CFStringRef (*copyDescription)(const void *info);
Boolean (*equal)(const void *info1, const void *info2);
CFHashCode (*hash)(const void *info);
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
mach_port_t (*getPort)(void *info);
void * (*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info);
#else
void * (*getPort)(void *info);
void (*perform)(void *info);
#endif
} CFRunLoopSourceContext1;
- version0和version1區(qū)別
當(dāng)我們接受到的消息(source),比如觸摸事件沃呢,滑動事件等等年栓;這個(gè)source是有兩種的,一種是version0薄霜,也就是用source0來表示某抓,一種是version1 -> source1
區(qū)別
version0 / source0 | source0 是非基于 port 的事件,主要是 APP 內(nèi)部事件惰瓜,如點(diǎn)擊事件否副,觸摸事件等 |
---|---|
version1 / source1 | source1 是基于Port的,通過內(nèi)核和其他線程通信崎坊,接收备禀,分發(fā)系統(tǒng)事件。 |
2.3. CFRunLoopObserverRef
一個(gè)指向__CFRunLoopObserver結(jié)構(gòu)體的指針
作用:觀察者,觀察runloop的各種狀態(tài)曲尸,并通過回調(diào)拋出去
struct __CFRunLoopObserver {
CFRuntimeBase _base;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFIndex _rlCount;
CFOptionFlags _activities; /* immutable */
CFIndex _order; /* immutable */
CFRunLoopObserverCallBack _callout; /* immutable */
CFRunLoopObserverContext _context; /* immutable, except invalidation */
};
其中的CFOptionFlags是一個(gè)枚舉:表示runloop的狀態(tài)
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 即將進(jìn)入loop
kCFRunLoopBeforeTimers = (1UL << 1), // 即將處理timer
kCFRunLoopBeforeSources = (1UL << 2), // 即將處理source
kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進(jìn)入休眠
kCFRunLoopAfterWaiting = (1UL << 6), // 剛從休眠中喚醒
kCFRunLoopExit = (1UL << 7), // 即將退出loop
kCFRunLoopAllActivities = 0x0FFFFFFFU // 占位
};
CFRunLoopObserverRef觀察者會將觀察到的狀態(tài)變化通過回調(diào)_callout
跑出去
看下這個(gè)CFRunLoopObserverCallBack _callout
// 這個(gè)回調(diào)可以將觀察者赋续、runloop狀態(tài)、info傳出去
typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
2.4. CFRunLoopTimerRef
是一個(gè)指向__CFRunLoopTimer結(jié)構(gòu)體的指針
某些數(shù)據(jù)類型能夠在Core Foundation和Foundation之間互換使用另患,可被互換使用的數(shù)據(jù)類型被稱為Toll-Free Bridged類型纽乱。
- CFRunLoopTimerRef 是定時(shí)器,可以在設(shè)定的時(shí)間點(diǎn)拋出回調(diào)
- CFRunLoopTimerRef和NSTimer是toll-free bridged的柴淘,可以相互轉(zhuǎn)換迫淹。
struct __CFRunLoopTimer {
CFRuntimeBase _base;
uint16_t _bits;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFMutableSetRef _rlModes;
CFAbsoluteTime _nextFireDate;
CFTimeInterval _interval; /* immutable */
CFTimeInterval _tolerance; /* mutable */
uint64_t _fireTSR; /* TSR units */
CFIndex _order; /* immutable */
CFRunLoopTimerCallBack _callout; /* immutable */
CFRunLoopTimerContext _context; /* immutable, except invalidation */
};
2.5.CFRunLoopModeRef
一個(gè)指向__CFRunLoopMode結(jié)構(gòu)體的指針
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* must have the run loop locked before locking this */
CFStringRef _name;
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
CFMutableDictionaryRef _portToV1SourceMap;
__CFPortSet _portSet;
CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
dispatch_source_t _timerSource;
dispatch_queue_t _queue;
Boolean _timerFired; // set to true by the source when a timer has fired
Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
mach_port_t _timerPort;
Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
DWORD _msgQMask;
void (*_msgPump)(void);
#endif
uint64_t _timerSoftDeadline; /* TSR */
uint64_t _timerHardDeadline; /* TSR */
};
- _sources0、 _sources1都是可變集合對象为严,對應(yīng)著用來存取
CFRunLoopSourceRef
對象敛熬,CFRunLoopSourceRef
對象中有version0
、version1
分別對應(yīng)著_sources0
和_sources1
- 包含了observer第股、timer
-
CFStringRef _name
就是mode的名字应民,如:kCFRunLoopDefaultMode
- 有幾種mode圖片來源
3.函數(shù)介紹
3.1.__CFRunLoopDoObservers
通知Observer,runloop要做什么事情
這個(gè)__CFRunLoopDoObservers
函數(shù)需要傳三個(gè)參數(shù)夕吻,分別是
- CFRunLoopRef(runloop對象)
- CFRunLoopModeRef(runloop的mode)
-
CFRunLoopActivity(runloop的狀態(tài)枚舉)
3.2._CFRunLoopGet0
runloop對象是存在全局字典中的诲锹,key就是pthread_t
這個(gè)_CFRunLoopGet0
函數(shù)的作用就是獲取對應(yīng)線程的runloop
實(shí)現(xiàn)思路(依據(jù)就是下面截圖的源碼)
1.先判斷這個(gè)全局字典存不存在,不存在涉馅,創(chuàng)建一個(gè)归园,并將主線程的runloop加進(jìn)去
2.直接去字典里取這個(gè)loop
3.如果loop不存在,就創(chuàng)建一個(gè)loop加入到全局字典中
// 偽代碼
if(!__CFRunLoops) {
1.創(chuàng)建全局字典
2.創(chuàng)建主線程loop稚矿,并加入到全局字典中
}
根據(jù)線程pthread_t為key庸诱,去字典取對應(yīng)的loop
if(!loop) {
1.創(chuàng)建loop
2.加入到字典中
}
return loop
其實(shí)這個(gè)說明了runloop和線程是一一對應(yīng)的關(guān)系
3.3.獲取主線程loop和獲取當(dāng)前的loop
參考文檔
強(qiáng)力推薦
RunLoop系列之要點(diǎn)提煉
RunLoop系列之源碼分析
iOS刨根問底-深入理解RunLoop
深入理解 RunLoop