RunLoop總結(jié)
1点楼、每個(gè)應(yīng)用都會(huì)有一個(gè)主線程煞聪,主線程對(duì)應(yīng)一個(gè)runloop卸夕,保證應(yīng)用一直在運(yùn)行
2、default模式的RunLoop是同通過(guò)do…while循環(huán)實(shí)現(xiàn)的
3截驮、獲取RunLopp對(duì)象笑陈,NSRunLoop是基于NSRunLoopRef的封裝
[NSRunLoop currentRunLoop]; // 獲得當(dāng)前線程的RunLoop對(duì)象
[NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對(duì)象
4、每一個(gè)Thread都對(duì)應(yīng)一個(gè)RunLoop葵袭,主線程的RunLoop會(huì)在創(chuàng)建的時(shí)候自動(dòng)創(chuàng)建涵妥,并且會(huì)保存在Dictionary中,線程的指針會(huì)作為key坡锡,RunLoop作為對(duì)應(yīng)的value蓬网。
子線程中使用currentRunLoop會(huì)獲取子線程對(duì)應(yīng)的RunLoop對(duì)象,如果沒(méi)有鹉勒,系統(tǒng)會(huì)自動(dòng)創(chuàng)建拳缠,并且保存在全局的Dictionary中。如果不獲取贸弥,不會(huì)自動(dòng)創(chuàng)建
5窟坐、一個(gè)RunLoop中包含了很多運(yùn)行modes,但是只能有一個(gè)currentMode绵疲,每個(gè)Mode包含了若干個(gè)Source0哲鸳、Source1、Timer盔憨、Observer
6徙菠、Mode中的Source0代表觸摸事件,Source1代表基于Port的線程間通信郁岩,Timer代表定時(shí)器婿奔,Observer監(jiān)聽(tīng)器(監(jiān)聽(tīng)RunLoop的狀態(tài))
7缺狠、系統(tǒng)默認(rèn)注冊(cè)了5種Mode,主線程默認(rèn)在DefaultMode下運(yùn)行
- kCFRunLoopDefaultMode:App的默認(rèn)Mode萍摊,通常主線程是在這個(gè)Mode下運(yùn)行
- UITrackingRunLoopMode:界面跟蹤 Mode挤茄,用于 ScrollView 追蹤觸摸滑動(dòng),保證界面滑動(dòng)時(shí)不受其他 Mode 影響
- UIInitializationRunLoopMode: 在剛啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode冰木,啟動(dòng)完成后就不再使用穷劈,會(huì)切換到kCFRunLoopDefaultMode
- GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到
- kCFRunLoopCommonModes: 這是一個(gè)占位用的Mode踊沸,作為標(biāo)記kCFRunLoopDefaultMode和UITrackingRunLoopMode用歇终,并不是一種真正的Mode
8、主線程中運(yùn)行的Timer逼龟,如果滑動(dòng)table或者TextView评凝,Timer會(huì)停止計(jì)數(shù),是因?yàn)镸ode自動(dòng)切換到了UITrackingRunLoopMode腺律,DefaultMode下的Timer就停止運(yùn)行了肥哎。可以使用KCFRunLoopCommonModes疾渣,使加入到主線程的Timer即可以在DefaultMode下運(yùn)行也可以在UITrackingRunLoopMode下運(yùn)行
9、使用GCD創(chuàng)建定時(shí)器
<colgroup><col style="width: 936px;"></colgroup>
|
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//創(chuàng)建隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//1.創(chuàng)建一個(gè)GCD定時(shí)器
/*
第一個(gè)參數(shù):表明創(chuàng)建的是一個(gè)定時(shí)器
第四個(gè)參數(shù):隊(duì)列
*/
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 需要對(duì)timer進(jìn)行強(qiáng)引用崖飘,保證其不會(huì)被釋放掉榴捡,才會(huì)按時(shí)調(diào)用block塊
// 局部變量,讓指針強(qiáng)引用
self.timer = timer;
//2.設(shè)置定時(shí)器的開(kāi)始時(shí)間,間隔時(shí)間,精準(zhǔn)度
/*
第1個(gè)參數(shù):要給哪個(gè)定時(shí)器設(shè)置
第2個(gè)參數(shù):開(kāi)始時(shí)間
第3個(gè)參數(shù):間隔時(shí)間
第4個(gè)參數(shù):精準(zhǔn)度 一般為0 在允許范圍內(nèi)增加誤差可提高程序的性能
GCD的單位是納秒 所以要*NSEC_PER_SEC
*/
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//3.設(shè)置定時(shí)器要執(zhí)行的事情
dispatch_source_set_event_handler(timer, ^{
NSLog(@"---%@--",[NSThread currentThread]);
});
// 啟動(dòng)
dispatch_resume(timer);
}
10朱浴、RunLoop主要包含下面五個(gè)類
* CFRunLoopRef - 獲取主RunLoop和CurrentRunLoop
* CFRunLoopModeRef - RunLoop運(yùn)行模式吊圾,可以有很多,但是只能選擇一個(gè)翰蠢,系統(tǒng)默認(rèn)定義了5種
* CFRunLoopSourceRef - 事件源项乒、輸入源
* CFRunLoopTimerRef - 定時(shí)器
* CFRunLoopObserverRef - 觀察RunLoop運(yùn)行狀態(tài)
11、CFRunLoopObserverRef可以觀測(cè)到RunLoop的整個(gè)生命周期梁沧,如下
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 即將進(jìn)入RunLoop
kCFRunLoopBeforeTimers = (1UL << 1), // 即將處理Timer
kCFRunLoopBeforeSources = (1UL << 2), // 即將處理Source
kCFRunLoopBeforeWaiting = (1UL << 5), //即將進(jìn)入休眠
kCFRunLoopAfterWaiting = (1UL << 6),// 剛從休眠中喚醒
kCFRunLoopExit = (1UL << 7),// 即將退出RunLoop
kCFRunLoopAllActivities = 0x0FFFFFFFU };
12檀何、RunLoop的處理邏輯
13、CFRunLoopRef種的使用do...while處理各種時(shí)間廷支,先處理Timers频鉴,然后Sources、Blocks恋拍、
14垛孔、RunLoop的處理邏輯
15、RunLoop的應(yīng)用施敢,常駐線程的使用
通過(guò)創(chuàng)建子線程周荐,并且在子線程中的RunLoop中加入Timer或者Source狭莱,使子線程一直存在,實(shí)現(xiàn)常駐線程
常駐線程可以用來(lái)記錄日志概作,或者上傳日志
17腋妙、CFRunLoop源碼
https://opensource.apple.com/tarballs/CF/
16、編寫測(cè)試代碼
- 查看各種事件調(diào)用的source
- 編寫代碼查看RunLoop的運(yùn)行狀態(tài)
- 實(shí)現(xiàn)常駐線程
參考文檔
1仆嗦、iOS底層原理總結(jié) - RunLoop