初识Runloop
1.runloop源碼
源碼
2.對象介紹
接下來的對象介紹,可以借助這個圖理清對象間的關系
// 一個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
一個指向__CFRunLoop結構體的指針
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 looppthread_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; }; 復制代碼從這個結構體的內容可以看出:
- 一個runloop對象主要包含modes、線程
- modes是一個可變集合,里面存著mode,所以一個runloop對象可以包含多個mode
- 一個 RunLoop 包含若干個 Mode,每個 Mode 又包含若干個 Source/Timer/Observer。(這三個的概念后面講)。每次調用 RunLoop 的主函數時,只能指定其中一個 Mode,這個Mode被稱作 CurrentMode。如果需要切換 Mode,只能退出 Loop,再重新指定一個 Mode 進入。這樣做主要是為了分隔開不同組的 Source/Timer/Observer,讓其互不影響。
2.2. CFRunLoopSourceRef
一個指向__CFRunLoopSource結構體的指針
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; }; 復制代碼-
結構體有一個_runLoops(可變包對象),說明一個source可以添加到多個runloop中
-
CFRunLoopSourceContext version0
- CFRunLoopSourceContext1 version1
- version0和version1區別 當我們接受到的消息(source),比如觸摸事件,滑動事件等等;這個source是有兩種的,一種是version0,也就是用source0來表示,一種是version1 -> source1 區別
| version1 / source1 | source1 是基于Port的,通過內核和其他線程通信,接收,分發系統事件。 |
2.3. CFRunLoopObserverRef
一個指向__CFRunLoopObserver結構體的指針 作用:觀察者,觀察runloop的各種狀態,并通過回調拋出去
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是一個枚舉:表示runloop的狀態
/* Run Loop Observer Activities */ typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {kCFRunLoopEntry = (1UL << 0), // 即將進入loopkCFRunLoopBeforeTimers = (1UL << 1), // 即將處理timerkCFRunLoopBeforeSources = (1UL << 2), // 即將處理sourcekCFRunLoopBeforeWaiting = (1UL << 5), // 即將進入休眠kCFRunLoopAfterWaiting = (1UL << 6), // 剛從休眠中喚醒kCFRunLoopExit = (1UL << 7), // 即將退出loopkCFRunLoopAllActivities = 0x0FFFFFFFU // 占位 };復制代碼CFRunLoopObserverRef觀察者會將觀察到的狀態變化通過回調_callout跑出去 看下這個CFRunLoopObserverCallBack _callout
// 這個回調可以將觀察者、runloop狀態、info傳出去 typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);復制代碼2.4. CFRunLoopTimerRef
是一個指向__CFRunLoopTimer結構體的指針
某些數據類型能夠在Core Foundation和Foundation之間互換使用,可被互換使用的數據類型被稱為Toll-Free Bridged類型。
- CFRunLoopTimerRef 是定時器,可以在設定的時間點拋出回調
- CFRunLoopTimerRef和NSTimer是toll-free bridged的,可以相互轉換。
2.5.CFRunLoopModeRef
一個指向__CFRunLoopMode結構體的指針
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_TIMERSdispatch_source_t _timerSource;dispatch_queue_t _queue;Boolean _timerFired; // set to true by the source when a timer has firedBoolean _dispatchTimerArmed; #endif #if USE_MK_TIMER_TOOmach_port_t _timerPort;Boolean _mkTimerArmed; #endif #if DEPLOYMENT_TARGET_WINDOWSDWORD _msgQMask;void (*_msgPump)(void); #endifuint64_t _timerSoftDeadline; /* TSR */uint64_t _timerHardDeadline; /* TSR */ };復制代碼- _sources0、 _sources1都是可變集合對象,對應著用來存取CFRunLoopSourceRef對象,CFRunLoopSourceRef對象中有version0、version1分別對應著_sources0和_sources1
- 包含了observer、timer
- CFStringRef _name就是mode的名字,如:kCFRunLoopDefaultMode
- 有幾種mode圖片來源
3.函數介紹
3.1.__CFRunLoopDoObservers
通知Observer,runloop要做什么事情 這個__CFRunLoopDoObservers函數需要傳三個參數,分別是
- CFRunLoopRef(runloop對象)
- CFRunLoopModeRef(runloop的mode)
- CFRunLoopActivity(runloop的狀態枚舉)
3.2._CFRunLoopGet0
runloop對象是存在全局字典中的,key就是pthread_t 這個_CFRunLoopGet0函數的作用就是獲取對應線程的runloop
實現思路(依據就是下面截圖的源碼) 1.先判斷這個全局字典存不存在,不存在,創建一個,并將主線程的runloop加進去 2.直接去字典里取這個loop 3.如果loop不存在,就創建一個loop加入到全局字典中 // 偽代碼 if(!__CFRunLoops) {1.創建全局字典2.創建主線程loop,并加入到全局字典中 } 根據線程pthread_t為key,去字典取對應的loop if(!loop) {1.創建loop2.加入到字典中 } return loop 復制代碼其實這個說明了runloop和線程是一一對應的關系
3.3.獲取主線程loop和獲取當前的loop
參考文檔
強力推薦 RunLoop系列之要點提煉 RunLoop系列之源碼分析 iOS刨根問底-深入理解RunLoop 深入理解 RunLoop
總結
- 上一篇: BZOJ3029守卫者的挑战(概率dp)
- 下一篇: LNMT部署详细步骤并实现动静分离和负载