什么是RunLoop?
從字面意思看:運行循環、跑圈
其實它內部就是do-while循環,在這個循環內部不斷地處理各種任務(比如Source、Timer、Observer)
閱讀CFRunloop源碼可見Runloop利用dowhile來實現的
image.png
image.png
Runloop運行原理圖
image.png
CFRunLoopMode
1. kCFRunLoopDefaultMode:App的默認Mode,通常主線程是在這個Mode下運行
2. UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響
3. UIInitializationRunLoopMode: 在剛啟動 App 時第進入的第一個 Mode,啟動完成后就不再使用
4. GSEventReceiveRunLoopMode: 接受系統事件的內部 Mode,通常用不到
5. kCFRunLoopCommonModes: 這是一個占位用的Mode,作為標記kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一種真正的Mode
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 */
};
CFRunLoopSourceRef
Source0:非基于Port的 用于用戶主動觸發的事件(點擊button 或點擊屏幕)
Source1:基于Port的 通過內核和其他線程相互發送消息(與內核相關)
注意:Source1在處理的時候會分發一些操作給Source0去處理
CFRunLoopObserverRef
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"RunLoop進入");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"RunLoop要處理Timers了");
break;
case kCFRunLoopBeforeSources:
NSLog(@"RunLoop要處理Sources了");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"RunLoop要休息了");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"RunLoop醒來了");
break;
case kCFRunLoopExit:
NSLog(@"RunLoop退出了");
break;
default:
break;
}
});