Runloop(運(yùn)行循環(huán))
-
1.1 字面意思
a 運(yùn)行循環(huán) b 跑圈 -
1.2 基本作用(作用重大)
a 保持程序的持續(xù)運(yùn)行--內(nèi)部就是do-while循環(huán),在這個(gè)循環(huán)內(nèi)部不斷地處理各種任務(wù)(比如Source、Timer、Observer) b 處理app中的各種事件(比如觸摸事件、定時(shí)器事件【NSTimer】、selector事件【選擇器·performSelector···】) c 節(jié)省CPU資源,提高程序性能,有事情就做事情,沒事情就休息 -
1.3 重要說明
(1)Runloop是程序一直存在并不斷處理事件的原因 (2)main函數(shù)中的Runloop a 在UIApplication函數(shù)內(nèi)部就啟動(dòng)了一個(gè)Runloop 該函數(shù)返回一個(gè)int類型的值 b 默認(rèn)啟動(dòng)的Runloop是跟主線程相關(guān)聯(lián)的 -
1.4 Runloop對(duì)象
(1)在iOS開發(fā)中有兩套api來訪問Runloop a.foundation框架【NSRunloop】 b.core foundation框架【CFRunloopRef】 (2)NSRunLoop和CFRunLoopRef都代表著RunLoop對(duì)象,它們是等價(jià)的,可以互相轉(zhuǎn)換 (3)NSRunLoop是基于CFRunLoopRef的一層OC包裝,所以要了解RunLoop內(nèi)部結(jié)構(gòu),需要多研究CFRunLoopRef層面的API(Core Foundation層面) 1.5 Runloop參考資料
(1)蘋果官方文檔
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html
(2)CFRunLoopRef開源代碼下載地址:
http://opensource.apple.com/source/CF/CF-1151.16/
-
1.6 Runloop與線程
1.Runloop和線程的關(guān)系:一個(gè)Runloop對(duì)應(yīng)著一條唯一的線程,一條線程最多有一個(gè)Runloop;開啟一個(gè)Runloop能讓子線程不死 2.Runloop的創(chuàng)建:主線程Runloop已經(jīng)創(chuàng)建好了,子線程的runloop需要手動(dòng)創(chuàng)建并開啟 3.Runloop的生命周期:在第一次獲取時(shí)創(chuàng)建,在線程結(jié)束時(shí)銷毀 1.7 獲得Runloop對(duì)象
1.獲得當(dāng)前Runloop對(duì)象
//01 NSRunloop
NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];
//02 CFRunLoopRef
CFRunLoopRef runloop2 = CFRunLoopGetCurrent();
2.拿到當(dāng)前應(yīng)用程序的主Runloop(主線程對(duì)應(yīng)的Runloop)
//01 NSRunloop
NSRunLoop * runloop1 = [NSRunLoop mainRunLoop];
//02 CFRunLoopRef
CFRunLoopRef runloop2 = CFRunLoopGetMain();
3.注意點(diǎn):開一個(gè)子線程創(chuàng)建runloop,不是通過alloc init方法創(chuàng)建,而是直接通過調(diào)用currentRunLoop方法來創(chuàng)建,它本身是一個(gè)懶加載的。如果不存在那么會(huì)自動(dòng)創(chuàng)建一個(gè)該線程對(duì)應(yīng)的runloop對(duì)象返回
4.在子線程中,如果不主動(dòng)獲取Runloop的話,那么子線程內(nèi)部是不會(huì)創(chuàng)建Runloop的。可以下載CFRunloopRef的源碼,搜索_CFRunloopGet0,查看代碼。
5.Runloop對(duì)象是利用字典來進(jìn)行存儲(chǔ),而且key是對(duì)應(yīng)的線程Value為該線程對(duì)應(yīng)的Runloop。
- 1.8 Runloop相關(guān)類
(1)Runloop運(yùn)行原理圖

(2)五個(gè)相關(guān)的類
a.CFRunloopRef
b.CFRunloopModeRef【Runloop的運(yùn)行模式】
c.CFRunloopSourceRef【Runloop要處理的事件源】
d.CFRunloopTimerRef【Timer事件】
e.CFRunloopObserverRef【Runloop的觀察者(監(jiān)聽者)】
http://www.itdecent.cn/p/78549ed1c24e
(3)Runloop和相關(guān)類之間的關(guān)系圖

(4)Runloop要想跑起來,它的內(nèi)部必須要有一個(gè)mode,這個(gè)mode里面必須有source\timer,至少要有其中的一個(gè)。
- 1.9 Runloop運(yùn)行邏輯
3.png


CF的內(nèi)存管理(Core Foundation)
凡是帶有Create、Copy、Retain等字眼的函數(shù),創(chuàng)建出來的對(duì)象,都需要在最后做一次release
比如CFRunLoopObserverCreate
release函數(shù):CFRelease(對(duì)象);
2.Runloop應(yīng)用
1)開啟NSTimer,控制定時(shí)器在特定模式下執(zhí)行
2)可以讓某些事件(行為、任務(wù))在特定模式下執(zhí)行,如ImageView顯示:控制方法在特定的模式下可用
3)PerformSelector:控制線程執(zhí)行不同的任務(wù)
4)常駐線程:讓一個(gè)子線程不進(jìn)入消亡狀態(tài),等待其他線程發(fā)來消息,處理其他事件
5)可以添加Observer監(jiān)聽RunLoop的狀態(tài),比如監(jiān)聽點(diǎn)擊事件的處理(在所有點(diǎn)擊事件之前做一些事情
6)自動(dòng)釋放池(可通過Observer監(jiān)聽RunLoop的狀態(tài))
第一次創(chuàng)建:進(jìn)入runloop的時(shí)候
最后一次釋放:runloop退出的時(shí)候
其它創(chuàng)建和釋放:當(dāng)runloop即將休眠的時(shí)候會(huì)把之前的自動(dòng)釋放池釋放,然后重新創(chuàng)建一個(gè)新的釋放池
3.常駐線程實(shí)現(xiàn)
/*
主線程對(duì)應(yīng)的runloop默認(rèn)已經(jīng)創(chuàng)建好了,但是子線程對(duì)應(yīng)的runloop需要手動(dòng)創(chuàng)建
子線程對(duì)應(yīng)的runloop還需要手動(dòng)的開啟,否則該runloop一創(chuàng)建出來就退出;在開啟前要先添加事件,否則也會(huì)退出。
保證mode里面有事件,不讓runloop立刻退出
可以往runloop中添加source和timer,但是添加observer是沒有作用的
*/
/*
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timer) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
*/
//創(chuàng)建子線程對(duì)應(yīng)的runloop并添加基于port的source
[[NSRunLoop currentRunLoop]addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
//開啟runloop,運(yùn)行在默認(rèn)模式下面(添加timer或是port都要開始runloop)
[[NSRunLoop currentRunLoop]run];
請(qǐng)簡單說明runloop中幾個(gè)類之間的相互關(guān)系(runloop & source & timer &observer &mode)
答:
1)runloop啟動(dòng)之后會(huì)選擇一種運(yùn)行模式,在執(zhí)行執(zhí)行會(huì)先檢查運(yùn)行模式內(nèi)部是否有source和timers,如果一個(gè)sourc或者是一個(gè)timer都沒有那么runlooop啟動(dòng)之后就立刻退出了。
2)runlooop的source有兩種分類方法,按照以前的分類方法可以分為
(1)基于端口的
(2)自定義的
(3)performSelector事件
按照函數(shù)調(diào)用棧來劃分,可以分為source0和soucr1。
3)observer,可以用來監(jiān)聽當(dāng)前runloop運(yùn)行狀態(tài)的改變,注意(Core foundation框架)
4)NSTimer必須添加到runloop中才會(huì)工作,且其工作收到runloop運(yùn)行模式的影響。