RunLoop(基礎(chǔ)部分)

在很多地方忿墅,都能看到這個(gè)概念融求,卻不知道到底是個(gè)什么玩意咬像,網(wǎng)上寫的也很抽象,理解起來(lái)很吃力生宛,官方文檔官方文檔也只是泛泛而談县昂。


那么,什么是RunLoop?

蘋果在取名方面我覺(jué)得非常不錯(cuò)陷舅,runloop就像字面上的意思一樣運(yùn)行循環(huán)倒彰,俗稱“兜圈圈”。也就是死循環(huán)莱睁,在這個(gè)循環(huán)中待讳,會(huì)去處理一系列的事件。假如說(shuō)這個(gè)循環(huán)停止了仰剿,那么程序就已經(jīng)停止了耙箍。

死循環(huán)

在創(chuàng)建一個(gè)工程,都會(huì)有個(gè)main函數(shù)酥馍,在這個(gè)函數(shù)里就是去運(yùn)行程序的時(shí)候創(chuàng)建了個(gè)主線程的RunLoop,也是保持程序持續(xù)運(yùn)行的關(guān)鍵辩昆。

如果改成return 0;那么程序?qū)⒉粫?huì)持續(xù)運(yùn)行,剛運(yùn)行就停止了旨袒。也不會(huì)去處理app的各種事件汁针,這也是為什么要去使用RunLoop了术辐,同樣,在其他操作系統(tǒng)上也有這個(gè)概念施无。

請(qǐng)問(wèn)這個(gè)打印會(huì)正常打印出來(lái)么辉词?可以先思考下為什么。

答案是不會(huì)打印的猾骡,因?yàn)樵谏弦痪淙鹛桑统伤姥h(huán),也就是弄了個(gè)runloop兴想,一直卡在上一句代碼幢哨,也就是保持了程序的持續(xù)運(yùn)行,如果說(shuō)能打印嫂便,那么return也能返回值捞镰,那么程序就沒(méi)法持續(xù)保持運(yùn)行,一旦返回值那么意味著結(jié)束毙替。


RunLoop有什么用呢岸售?

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

2.處理App的各種事件(比如觸摸事件、定時(shí)器事件厂画、Selector事件)

3.節(jié)省CPU資源凸丸,提高程序性能。(該做事的時(shí)候做事袱院,該休息的時(shí)候休息)


RunLoop對(duì)象

在iOS中有2套API去訪問(wèn)和使用RunLoop

Foundation框架

NSRunLoop

Core Foundation框架

CFRunLoopRef

NSRunLoop和CFRunLoopRef都代表RunLoop對(duì)象屎慢,NSRunLoop是基于CFRunLoopRef的一層OC封裝,為此要理解RunLoop內(nèi)部結(jié)構(gòu)坑填,要多研究CFRunLoopRef

NSRrunLoop缺點(diǎn):效率低(因?yàn)槭巧蠈臃庋b)抛人,封裝的不算好弛姜,可提供的方法很少脐瑰。

CFRunLoopRef是開(kāi)源的,開(kāi)源地址CFRunLoopRef開(kāi)源地址


RunLoop和線程

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

2.主線程的RunLoop已經(jīng)自動(dòng)創(chuàng)建好了廷臼,子線程的RunLoop需要主動(dòng)創(chuàng)建(默認(rèn)關(guān)閉的)

3.RunLoop在第一次獲取時(shí)創(chuàng)建苍在,在線程結(jié)束時(shí)銷毀。


如何獲取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)類

類層次結(jié)構(gòu)圖

Core Foundation中關(guān)于RunLoop有5個(gè)類

CFRunLoopRef

CFRunLoopModeRef

CFRunLoopSourceRef

CFRunLoopTimerRef ?

CFRunLoopObserverRef

RunLoop中有多個(gè)Mode荠商,可以在多個(gè)Mode中來(lái)回切換寂恬,Mode是RunLoop重要的組成部分,沒(méi)有Mode,RunLoop就跑不起來(lái).

在一個(gè)Mode里莱没,不是必須Source,Timer,Observer三個(gè)必須有值初肉,有一個(gè)有值,RunLoop也是可以跑起來(lái)的饰躲。


CFRunLoopModeRef

1.CFRunLoopModeRef代表RunLoop的運(yùn)行模式

2.一個(gè)RunLoop包含若干個(gè)Mode牙咏,每個(gè)Mode又包含若干個(gè)Source/Timer/Observer

3.每次RunLoop啟動(dòng)時(shí)臼隔,只能指定其中一個(gè)Mode,這個(gè)Mode又叫做CurrentMode

4.如果需要切換Mode妄壶,只能退出Loop摔握,再重新指定一個(gè)Mode進(jìn)入Loop。這樣做主要是為了分隔不同組的Source/Timer/Observer丁寄,讓其互不影響氨淌。

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

kCFRunLoopDefaultMode:app默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行

UITrackingRunLoopMode:界面跟蹤Mode伊磺,用于Scrollview追蹤觸摸滑動(dòng)盛正,保證界面滑動(dòng)不受其他Mode影響

UIInitializationRunLoopMode:在剛啟動(dòng)App時(shí)進(jìn)入的第一個(gè)Mode,啟動(dòng)完成后就不再使用

GSEventReceiveRunLoopMode:接受系統(tǒng)時(shí)間的內(nèi)部Mode奢浑,通常用不到

kCFRunLoopCommonModes:這是一個(gè)占位用的Mode蛮艰,不是一種真正的Mode,即可能kCFRunLoopDefaultMode雀彼,也可能是UITrackingRunLoopMode

例子:

當(dāng)不去滑動(dòng)TextView時(shí)壤蚜,當(dāng)前RunLoopMode是NSDefaultMode,所以定時(shí)器會(huì)正常運(yùn)作徊哑;當(dāng)去滑動(dòng)TextView時(shí)袜刷,當(dāng)前RunLoopMode切換到UITrackingRunLoopMode,定時(shí)器又要在NSDefaultMode模式下才能運(yùn)行莺丑,所以定時(shí)器失效著蟹;當(dāng)不再滑動(dòng),又切換到NSDefaultMode梢莽,定時(shí)器又可以正常運(yùn)作萧豆。

我們知道了是因?yàn)镽unLoop模式導(dǎo)致了,所以昏名,將定時(shí)器在的模式更改就行了涮雷。

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];


CFRunLoopSourceRef

Mode的一個(gè)組成部分,CFRunLoopSourceRef被稱為事件源(輸入源)轻局。RunLoopSource包括2種source:分別為Source0Source1洪鸭。

Source0:非基于port的

只包含了一個(gè)回調(diào)(函數(shù)指針),它并不能主動(dòng)觸發(fā)事件仑扑。使用時(shí)览爵,你需要先調(diào)用。(通俗點(diǎn)說(shuō):1.自定義的事件镇饮,自己寫的事件蜓竹;2.PerformSelecter事件)

Source1:基于port的

包含了一個(gè) mach_port 和一個(gè)回調(diào)(函數(shù)指針),被用于通過(guò)內(nèi)核和其他線程相互發(fā)送消息。這種 Source 能主動(dòng)喚醒 RunLoop 的線程(簡(jiǎn)單地說(shuō):系統(tǒng)做的事件)

(補(bǔ)充:port就是端口內(nèi)核的意思俱济,也可以理解為cpu)

上圖是我在storyboard拖的button事件方法司蔬,通過(guò)設(shè)置斷點(diǎn),可以看到線程棧的情況姨蝴,很清楚的看到Source0俊啼,也可以說(shuō)明,事件源是由自定義寫的左医。


CFRunLoopTimerRef

基于時(shí)間的觸發(fā)器(說(shuō)白了授帕,基本就是NSTimer)


CFRunLoopObserverRef

CFRunLoopObserverRef是觀察者,能夠監(jiān)聽(tīng)RunLoop的狀態(tài)改變

可以監(jiān)聽(tīng)的時(shí)間點(diǎn)有下面幾個(gè)

/*Run Loop Observer Activities*/

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 << 8), ?//剛從休眠中喚醒

? ? ? ?kCFRunLoopExit = (1UL << 7), ? ? ? ? //即將退出RunLoop

? ? ? ?kCFRunLoopAllActivities = 0x0FFFFFFFU ? //監(jiān)聽(tīng)RunLoop所有情況

}

如何去創(chuàng)建一個(gè)ObserverRef

列1:我們來(lái)看看應(yīng)用從啟動(dòng)到界面顯示浮梢,runloop狀態(tài)是如何變化的跛十。

可以看到,從最開(kāi)始的1(即將進(jìn)入RunLoop)到最后的32(即將進(jìn)入休眠)一個(gè)過(guò)程秕硝。

列1:我們來(lái)監(jiān)聽(tīng)下一個(gè)按鈕點(diǎn)擊后芥映,RunLoop狀態(tài)的變化

可以看到,從最開(kāi)始的64(剛從休眠喚醒)到最后的32(即將進(jìn)入休眠)远豺。

為此奈偏,我們可以利用runloop的狀態(tài)改變來(lái)處理一些不好處理的事件,具體需要具體情況而定躯护,這樣runloop就可以很好的結(jié)合起來(lái)使用了惊来。


知道了RunLoop邏輯處理和RunLoop結(jié)構(gòu)后,我們來(lái)看看官方提供的RunLoop處理邏輯圖就很好理解了棺滞。

左圖的就是RunLoop裁蚁,Runloop是跟線程一一綁定的,所以是個(gè)Thread继准。然后Runloop一直跑圈枉证,在跑圈的過(guò)程中,右圖會(huì)有Sources傳入進(jìn)行事件操作移必,如Timer室谚,基于Port事件,自定義事件避凝,performSelector事件舞萄。

RunLoop處理邏輯過(guò)程


總結(jié):

? ? 1.主線程的RunLoop默認(rèn)開(kāi)啟

? ? 2.子線程的RunLoop默認(rèn)關(guān)閉眨补,需要手動(dòng)開(kāi)啟

? ? 3.RunLoop開(kāi)啟的時(shí)候要包含Mode管削,必須要某個(gè)確定的模式下運(yùn)行,同時(shí)在一個(gè)模式下運(yùn)行

? ? 4.observer可以監(jiān)聽(tīng)RunLoop所有狀態(tài)事件撑螺,可以做到一些別人做不到的事含思。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子含潘,更是在濱河造成了極大的恐慌饲做,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遏弱,死亡現(xiàn)場(chǎng)離奇詭異盆均,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)漱逸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門泪姨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人饰抒,你說(shuō)我怎么就攤上這事肮砾。” “怎么了袋坑?”我有些...
    開(kāi)封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵仗处,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我枣宫,道長(zhǎng)婆誓,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任也颤,我火速辦了婚禮蜈漓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘迈倍。我一直安慰自己追城,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布故觅。 她就那樣靜靜地躺著厂庇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪输吏。 梳的紋絲不亂的頭發(fā)上权旷,一...
    開(kāi)封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音贯溅,去河邊找鬼拄氯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛它浅,可吹牛的內(nèi)容都是我干的译柏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼姐霍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鄙麦!你這毒婦竟也來(lái)了典唇?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤胯府,失蹤者是張志新(化名)和其女友劉穎介衔,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體骂因,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡炎咖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寒波。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片塘装。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖影所,靈堂內(nèi)的尸體忽然破棺而出蹦肴,到底是詐尸還是另有隱情,我是刑警寧澤猴娩,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布阴幌,位于F島的核電站,受9級(jí)特大地震影響卷中,放射性物質(zhì)發(fā)生泄漏矛双。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一蟆豫、第九天 我趴在偏房一處隱蔽的房頂上張望议忽。 院中可真熱鬧,春花似錦十减、人聲如沸栈幸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)速址。三九已至,卻和暖如春由驹,著一層夾襖步出監(jiān)牢的瞬間芍锚,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工蔓榄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留并炮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓甥郑,卻偏偏與公主長(zhǎng)得像逃魄,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子壹若,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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

  • Run loop 剖析:Runloop 接收的輸入事件來(lái)自兩種不同的源:輸入源(intput source)和定時(shí)...
    Mitchell閱讀 12,411評(píng)論 17 111
  • 前言 最近離職了,可以盡情熬夜寫點(diǎn)總結(jié)嗅钻,不用擔(dān)心第二天上班爽并蛋疼著,這篇的主角 RunLoop 一座大山店展,涵蓋的...
    zerocc2014閱讀 12,367評(píng)論 13 67
  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20150601/11970.html RunL...
    Gatling閱讀 1,435評(píng)論 0 13
  • 一养篓、什么是runloop 字面意思是“消息循環(huán)、運(yùn)行循環(huán)”赂蕴。它不是線程柳弄,但它和線程息息相關(guān)。一般來(lái)講概说,一個(gè)線程一次...
    WeiHing閱讀 8,107評(píng)論 11 111
  • 前言 今天在適配Android6.0時(shí)遇到兩個(gè)問(wèn)題碧注,比較典型,總結(jié)下來(lái)糖赔,以備后用 -- 好腦子不如爛筆頭萍丐! 問(wèn)題一...
    Sealwk閱讀 417評(píng)論 0 1