--------------------RunLoop--------------------
什么是RunLoop
運(yùn)行循環(huán),在程序運(yùn)行過(guò)程中循環(huán)做一些事情
RunLoopde 應(yīng)用范疇
定時(shí)器(Timer)、PerformSelector
GCD Async Main Queue
事件響應(yīng)、手勢(shì)識(shí)別、界面刷新
網(wǎng)絡(luò)請(qǐng)求
AutoreleasePool
RunLoop與線程
- 每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的RunLoop對(duì)象
- RunLoop保存在一個(gè)全局的Dictionary里,線程作為key,RunLoop作為value
- 線程剛創(chuàng)建時(shí)并沒(méi)有RunLoop對(duì)象,RunLoop會(huì)在第一次獲取它時(shí)創(chuàng)建
- RunLoop會(huì)在線程結(jié)束時(shí)銷毀
- 主線程的RunLoop已經(jīng)自動(dòng)獲?。▌?chuàng)建),子線程默認(rèn)沒(méi)有開(kāi)啟RunLoop
獲得RunLoop對(duì)象
Foundation
[NSRunLoop currentRunLoop]; // 獲得當(dāng)前線程的RunLoop對(duì)象
[NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對(duì)象
Core Foundation
CFRunLoopGetCurrent(); // 獲得當(dāng)前線程的RunLoop對(duì)象
CFRunLoopGetMain(); // 獲得主線程的RunLoop對(duì)象
RunLoop相關(guān)的5個(gè)類:
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef
CFRunLoop和 CFRunLoopMode
// CFRunLoop.h
typedef struct __CFRunLoop * CFRunLoopRef;
// CFRunLoop.c
struct __CFRunLoop {
pthread_t _pthread; // 與線程一一對(duì)應(yīng)
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
...
};
// 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
...
};
CFRunLoopModeRef
- CFRunLoopModeRef代表RunLoop的運(yùn)行模式
- 一個(gè)RunLoop包含若干個(gè)Mode,每個(gè)Mode又包含若干個(gè)Source0/Source1/Timer/Observer
- RunLoop啟動(dòng)時(shí)只能選擇其中一個(gè)Mode,作為currentMode
- 如果需要切換Mode,只能退出當(dāng)前Loop,再重新選擇一個(gè)Mode進(jìn)入
不同組的Source0/Source1/Timer/Observer能分隔開(kāi)來(lái),互不影響 - 如果Mode里沒(méi)有任何Source0/Source1/Timer/Observer,RunLoop會(huì)立馬退出
常見(jiàn)的兩種mode:
- kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行
- UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動(dòng),保證界面滑動(dòng)時(shí)不受其他 Mode 影響
CFRunLoopObserverRef
/* 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)
};
添加RunLoop的監(jiān)聽(tīng):
// 創(chuàng)建Observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
switch (activity) {
case kCFRunLoopEntry: {
NSLog(@"kCFRunLoopEntry");
break;
}
case kCFRunLoopBeforeTimers: {
NSLog(@"kCFRunLoopEntry");
} break;
case kCFRunLoopBeforeSources: {
NSLog(@"kCFRunLoopEntry");
} break;
case kCFRunLoopBeforeWaiting: {
NSLog(@"kCFRunLoopEntry");
} break;
case kCFRunLoopAfterWaiting: {
NSLog(@"kCFRunLoopEntry");
} break;
case kCFRunLoopExit: {
NSLog(@"kCFRunLoopExit");
break;
}
default:
break;
}
});
// 添加Observer到RunLoop中
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
// 釋放
CFRelease(observer);
RunLoop的運(yùn)行邏輯
先上一張老圖

image.png
Source0
觸摸事件處理
performSelector:onThread:Source1
基于Port的線程間通信
系統(tǒng)事件捕捉Timers
NSTimer
performSelector:withObject:afterDelay:Observers
用于監(jiān)聽(tīng)RunLoop的狀態(tài)
UI刷新(BeforeWaiting)
Autorelease pool(BeforeWaiting)
過(guò)程:

image.png