RunLoop

一栈雳、RunLoop的基本概念:

runloop從字面的意思來(lái)看就是:運(yùn)行循環(huán)。

runloop的基本作用:

1、保持程序的持續(xù)運(yùn)行

2媒楼、處理app中各種事件(觸摸事件、定時(shí)器事件戚丸、Selector事件等)

3划址、能節(jié)省CPU,提高程序的性能:該做事的時(shí)候就被喚醒限府,沒(méi)有事情就睡眠

假如沒(méi)有了runloop夺颤,程序會(huì)在main函數(shù)執(zhí)行完畢后退出,正是因?yàn)橛辛藃unloop胁勺,導(dǎo)致主函數(shù)沒(méi)有馬上退出世澜,保證了程序持續(xù)運(yùn)行。簡(jiǎn)單的可以理解為

二署穗、RunLoop對(duì)象

iOS中有2套API來(lái)訪問(wèn)和使用RunLoop

1寥裂、Foundation框架中的NSRunLoop

2、Core Foundation中的CFRunLoop

NSRunLoop是基于CFRunLoop的一層OC包裝案疲。但是NSRunLoop不是線程安全的封恰,而CFRunLoopRef是線程安全的。

三褐啡、RunLoop與線程

1诺舔、每條線程都有唯一的一個(gè)與之相對(duì)應(yīng)的RunLoop對(duì)象

2、主線程的RunLoop由系統(tǒng)自動(dòng)創(chuàng)建备畦,子線程的RunLoop可以手動(dòng)創(chuàng)建低飒。

3、RunLoop在線程結(jié)束的時(shí)候會(huì)被銷(xiāo)毀懂盐。

獲取RunLoop對(duì)象

四逸嘀、RunLoop的結(jié)構(gòu)


首先我們需要知道的是CFRunLoop有五大類(lèi):

1、CFRunLoopRef?

2允粤、CFRunLoopMod

3崭倘、CFRunLoopObserverRef

4翼岁、CFRunLoopSourceRef

5、CFRunLoopTimerRef

下邊我們一一介紹上邊的5大類(lèi):

1司光、CFRunLoopRef:一個(gè)RunLoop對(duì)象琅坡,沒(méi)啥好解釋的。

2残家、CFRunLoopMod榆俺。這個(gè)mode咱們好好聊聊。

CFRunLoopMod代表RunLoop的運(yùn)行模式坞淮。

(1)一個(gè)RunLoop中包含多個(gè)Mode茴晋,每個(gè)Mode中又包含了多個(gè)Source/Timer/Observer。

(2)一個(gè)RunLoop在同一時(shí)間只能處在一種運(yùn)行模式下回窘,這個(gè)模式就是CurrentMode诺擅。

(3)如果切換Mode,只能退出當(dāng)前的RunLoop啡直,主要是為了分隔開(kāi)不同組的Source/Timer/Observer烁涌。

系統(tǒng)默認(rèn)注冊(cè)了5種Mode

這里就遇到一個(gè)面試題:調(diào)用+scheduledTimerWithTimeInterval...的方式觸發(fā)的timer,在滑動(dòng)頁(yè)面上的列表是酒觅,timer會(huì)暫停調(diào)用撮执,為什么?如何解決的舷丹?

答:我們知道抒钱,一個(gè)timer在NSDefaultMode下被觸發(fā),如果這個(gè)時(shí)候拖動(dòng)scrollview的話颜凯,這個(gè)timer就失效了继效,因?yàn)橥蟿?dòng)scrollview,RunLoop的mode切換為UITrackingRunLoopMode装获。如果想要讓一個(gè)定時(shí)器在兩個(gè)模式下都有效有兩種方法:1瑞信、將它加入到兩個(gè)mode中;2穴豫、將timer加入到頂層的RunLoop的commonModeItems集合中凡简,RunLoop會(huì)自動(dòng)將這個(gè)集合中的所有item同步到具有"common"標(biāo)示的mode。

第一種方案的代碼:(是mainRunLoop還是currentMode還是需要自己做判斷的)

第二種方案的代碼:

3精肃、CFRunLoopObserver:RunLoop狀態(tài)的觀察者秤涩,每一個(gè)觀察者都包含一個(gè)回調(diào)(指針函數(shù)),當(dāng)RunLoop的狀態(tài)發(fā)生變化時(shí)司抱,觀察者就能通過(guò)回調(diào)接收這個(gè)變化筐眷。觀察狀態(tài)由以下幾種:

有了這個(gè)觀察者,就有了下邊咱們要說(shuō)到的RunLoop的處理邏輯习柠。(這里是不是想到了ViewController的生命周期匀谣?)

4照棋、CFRunLoopSourceRef:事件產(chǎn)生的地方

按照函數(shù)調(diào)用棧分為兩類(lèi):Source0、Source1

Source0非基于Port的武翎。只包含一個(gè)回調(diào)函數(shù)指針烈炭,使用時(shí)需要將事件標(biāo)記為待處理:CFRunLoopSourceSignal(source),再調(diào)用CFRunLoopWakeUP(runloop)來(lái)喚醒RunLoop宝恶,使其處理整個(gè)事件

Source1基于Port的符隙。通過(guò)內(nèi)核和其他線程通信,接收垫毙、分發(fā)系統(tǒng)事件霹疫。

5、CFRunLoopTimerRef:基于時(shí)間的觸發(fā)器综芥。

說(shuō)到定時(shí)器丽蝎,有一種說(shuō)法,說(shuō)RunLoop的timer和GCD中的timer是一個(gè)東西毫痕,其實(shí)不是的征峦。CFRunLoopTimer基本上說(shuō)的就是NSTimer迟几,它受RunLoop Mode的影響消请。

GCD定時(shí)器不受RunLoop Mode的影響

五类腮、RunLoop的處理邏輯

上圖右邊是線程的輸入源:(這個(gè)輸入源是不是和上邊說(shuō)的CFRunLoopSourceRef:事件產(chǎn)生的地方有什么聯(lián)系半)

(1)基于端口的輸入源(Port Sources)

(2)自定義輸入源(Custom Sources)

(3)Cocoa執(zhí)行Selector的源(performSelectorxxx方法)

(4)定時(shí)源(Timer Sources)

線程針對(duì)上邊不同的輸入源,又不同的處理機(jī)制

(1)handlePort——處理基于端口的輸入源

(2)customSrc——處理用戶(hù)自定義輸入源

(3)mySelector——處理Selector的源

(4)timerFired——處理定時(shí)源

上邊是官方邏輯蚜枢,下邊的是非官方邏輯缸逃,從非官方邏輯里面我們可以看到我們上邊說(shuō)到的CFRunLoop的五大類(lèi)都在什么時(shí)候用

六、RunLoop的具體使用

(1)事件傳遞與手勢(shì)識(shí)別

對(duì)于硬件事件(觸摸厂抽、鎖屏需频、搖晃)的處理,蘋(píng)果注冊(cè)了一個(gè)基于port的source1筷凤,它的回調(diào)函數(shù)是__IOHIDEventSystemClientQueueCallback()昭殉,事件發(fā)生后,系統(tǒng)將事件包裝成IOHIDEvent對(duì)象藐守,并由mach port分配到對(duì)應(yīng)的APP進(jìn)程中挪丢,隨后觸發(fā)source1的回調(diào),并調(diào)用_UIApplicationHandleEventQueueCallback()進(jìn)行內(nèi)部分發(fā)卢厂,其中包括識(shí)別 UIGesture/處理屏幕旋轉(zhuǎn)/發(fā)送給 UIWindow 等乾蓬,接下來(lái)發(fā)生的響應(yīng)者鏈條了。

對(duì)于手勢(shì)識(shí)別:當(dāng)_UIApplicationHandleQueueCallback()接收到手勢(shì)的時(shí)候慎恒,會(huì)將TouchBegin等事件的回調(diào)打斷任内,隨后會(huì)將這個(gè)手勢(shì)標(biāo)記為待處理狀態(tài)撵渡,同時(shí)注冊(cè)一個(gè)observer,檢測(cè)BeforeWaiting狀態(tài)族奢,當(dāng)RunLoop即將進(jìn)入休眠時(shí)姥闭,其內(nèi)部會(huì)獲取到剛才所有標(biāo)記為待處理的手勢(shì),執(zhí)行_UIGestureRecognizerUpdateQueue()越走。

(2)Autorealease

iOS中autorelease變量什么時(shí)候釋放棚品,應(yīng)該分為兩種情況:

手動(dòng)釋放@autoreleasepool { }中的自動(dòng)釋放變量在當(dāng)前大括號(hào)作用域結(jié)束時(shí)釋放;

系統(tǒng)釋放:在當(dāng)前RunLoop本次Loop結(jié)束后釋放廊敌;

autorelease原理:

(3)頁(yè)面刷新

當(dāng)在操作 UI 時(shí)铜跑,比如改變了 Frame、更新了 UIView/CALayer 的層次時(shí)骡澈,或者手動(dòng)調(diào)用了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法后锅纺,這個(gè) UIView/CALayer 就被標(biāo)記為待處理,并被提交到一個(gè)全局的容器去肋殴。

蘋(píng)果注冊(cè)了一個(gè) Observer 監(jiān)聽(tīng) BeforeWaiting(即將進(jìn)入休眠) 和 Exit (即將退出Loop) 事件囤锉,回調(diào)去執(zhí)行:

_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()。這個(gè)函數(shù)里會(huì)遍歷所有待處理的 UIView/CAlayer 以執(zhí)行實(shí)際的繪制和調(diào)整护锤,并更新 UI 界面官地。在這個(gè)函數(shù)之后就在屏幕上看到UI的變化。

圖片刷新(假如界面要刷新N多圖片需要渲染)烙懦,此時(shí)用戶(hù)拖拽UI控件就會(huì)出現(xiàn)卡的效果驱入,我們可以通過(guò)RunLoop實(shí)現(xiàn),只在RunLoop默認(rèn)Mode下下載氯析,也就是拖拽Mode下不刷新圖片)

(4)Timer

可以說(shuō)沒(méi)有RunLoop就不可能實(shí)現(xiàn)定時(shí)器的功能亏较。定時(shí)器的大致原理:設(shè)定一個(gè)時(shí)間點(diǎn),將定時(shí)器加入RunLoop中掩缓,等到達(dá)設(shè)定的時(shí)間點(diǎn)的時(shí)候回喚醒線程處理回調(diào)雪情。

(5)PerfromSeletor:afterDelay:

如果當(dāng)前線程中沒(méi)有RunLoop這個(gè)方法是不會(huì)有效的,本質(zhì)上是在當(dāng)前線程的RunLoop中添加一個(gè)定時(shí)器你辣,當(dāng)時(shí)間點(diǎn)到了會(huì)喚醒RunLoop執(zhí)行回調(diào)巡通。

(6)dispatch_main_queue

當(dāng)調(diào)用dispatch_async(dispatch_get_main_queue(), block)時(shí),libDispatch 會(huì)向主線程的 RunLoop 發(fā)送消息绢记,RunLoop會(huì)被喚醒扁达,并從消息中取得這個(gè) block,并在回調(diào)__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__()里執(zhí)行這個(gè) block蠢熄。但這個(gè)邏輯僅限于 dispatch 到主線程跪解,dispatch 到其他線程仍然是由 libDispatch 處理的。

(7)保證一個(gè)線程永遠(yuǎn)不死

結(jié)束。謝謝叉讥。





總的來(lái)說(shuō)窘行,這個(gè)RunLoop比RunTime要容易一些,可能是因?yàn)橛玫降牡胤奖容^多图仓,另外能夠看到罐盔,不像RunTime藏的很深的樣子。

該問(wèn)借鑒了:(1)RunLoop

? ? ? ? ? ? ? ? ? ?(2)RunLoop

有興趣的可以去看看這個(gè):深入理解RunLoop

在這里感謝上邊兩位作者救崔,如果有版權(quán)問(wèn)題惶看,可以聯(lián)系我。謝謝六孵。

最后纬黎,哪里不對(duì)的地方可以給我留言,我會(huì)及時(shí)改進(jìn)的劫窒,謝謝大家本今。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市主巍,隨后出現(xiàn)的幾起案子冠息,更是在濱河造成了極大的恐慌,老刑警劉巖孕索,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逛艰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡檬果,警方通過(guò)查閱死者的電腦和手機(jī)瓮孙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)唐断,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)选脊,“玉大人,你說(shuō)我怎么就攤上這事脸甘】疑叮” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵丹诀,是天一觀的道長(zhǎng)钝的。 經(jīng)常有香客問(wèn)我,道長(zhǎng)铆遭,這世上最難降的妖魔是什么硝桩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮枚荣,結(jié)果婚禮上碗脊,老公的妹妹穿的比我還像新娘。我一直安慰自己橄妆,他們只是感情好衙伶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布祈坠。 她就那樣靜靜地躺著,像睡著了一般矢劲。 火紅的嫁衣襯著肌膚如雪赦拘。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天芬沉,我揣著相機(jī)與錄音躺同,去河邊找鬼。 笑死丸逸,一個(gè)胖子當(dāng)著我的面吹牛笋籽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播椭员,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼车海,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了隘击?” 一聲冷哼從身側(cè)響起侍芝,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎埋同,沒(méi)想到半個(gè)月后州叠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凶赁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年咧栗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虱肄。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡致板,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出咏窿,到底是詐尸還是另有隱情斟或,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布集嵌,位于F島的核電站萝挤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏根欧。R本人自食惡果不足惜怜珍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凤粗。 院中可真熱鬧酥泛,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至瘦馍,卻和暖如春歼秽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背情组。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工燥筷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人院崇。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓肆氓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親底瓣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谢揪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容