RunLoop

RunLoop

Runloop 是和線程緊密相關(guān)的一個(gè)基礎(chǔ)組件筹煮,是很多線程有關(guān)功能的幕后功臣。盡管在平常使用中幾乎不太會(huì)直接用到族扰,理解 Runloop 有利于我們更加深入地理解 iOS 的多線程模型大猛。

目的:保住當(dāng)前線程的生命,監(jiān)聽事件:觸摸、時(shí)鐘薪缆、網(wǎng)絡(luò)等

RunLoop基本概念

RunLoop是什么?顧名思義伞广,說(shuō)白了就是一種循環(huán)拣帽,只不過(guò)它這種循環(huán)比較高級(jí)。一般的while循環(huán)會(huì)導(dǎo)致CPU進(jìn)入忙等待狀態(tài)嚼锄,而Runloop則是一種“閑”等待减拭,這部分可以類比Linux下的epoll。當(dāng)沒(méi)事件時(shí)区丑,Runloop會(huì)進(jìn)入休眠狀態(tài)峡谊,有事件發(fā)生時(shí),Runloop會(huì)去找對(duì)應(yīng)的Handler處理事件刊苍。Runloop可以讓線程在需要做事的時(shí)候忙起來(lái),不需要的話就讓線程休眠濒析。


Structure of a run loop and its sources

圖中展示了Runloop在線程中的作用:從 input source 和 timer source 接受事件正什,然后在線程中處理事件。

Runloop 與線程

Runloop 和線程是綁定在一起的号杏。每個(gè)線程(包括主線程)都有一個(gè)對(duì)應(yīng)的Runloop對(duì)象婴氮。我們并不能自己創(chuàng)建Runloop對(duì)象斯棒,但是可以獲取到系統(tǒng)提供的Runloop對(duì)象。
主線程的 Runloop 會(huì)在應(yīng)用啟動(dòng)的時(shí)候完成啟動(dòng)主经,其他線程的 Runloop 默認(rèn)并不會(huì)啟動(dòng)荣暮,需要我們手動(dòng)啟動(dòng)。

Input Source 和 Timer Source

這兩個(gè)都是 Runloop 時(shí)間的來(lái)源罩驻,其中Input Source 又可以分為三類

  • Port-Base Source穗酥,系統(tǒng)底層的Port時(shí)間,例如CFSocketRef惠遏,在應(yīng)用層基本用不到
  • Custom Input Source砾跃,用戶手動(dòng)創(chuàng)建的Source
  • Cocoa Perform Selector Source,Cacoa提供的的performSelector系列方法节吮,也是一種事件源

按照函數(shù)調(diào)用棧,Source可分為 Source0Source1抽高。其中 Source1 為系統(tǒng)內(nèi)核事件, Source0即非Source1

例如:創(chuàng)建事件源

    //隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(0,0);
    //創(chuàng)建一個(gè)定時(shí)器!!
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    //設(shè)置定時(shí)器
    dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1000000000, 0);
    dispatch_source_set_event_handler(self.timer, ^{
        NSLog(@"-------%@",[NSThread currentThread]);
    });
    //啟動(dòng)定時(shí)器
    dispatch_resume(self.timer);

Timer Source 顧名思義就是指定時(shí)器事件了。例如:NStimer 創(chuàng)建定時(shí)器

Runloop Observer

Runloop 通過(guò)監(jiān)控Source來(lái)決定有沒(méi)有任務(wù)要做透绩,除此之外翘骂,我們還可以用Runloop Observer 可以監(jiān)控下面的 runloop 事件:

  • The entrance to the run loop.
  • When the run loop is about to process a timer.
  • When the run loop is about to process an input source.
  • When the run loop is about to go to sleep.
  • When the run loop has woken up, but before it has processed the event that woke it up.
  • The exit from the run loop.

通過(guò)Runloop Observer 可以實(shí)現(xiàn)卡頓優(yōu)化,如:TableView滑動(dòng)中加載多張大圖
思路:每次Runloop循環(huán),只渲染一張大圖
步驟:
1.監(jiān)聽Runloop的循環(huán)
2.將加載大圖的代碼!放在一個(gè)數(shù)組里面
3.每次Runloop循環(huán),取出一個(gè)加載大圖的任務(wù)執(zhí)行

#pragma mark - <CFRunloop>

- (void)addTasks:(runloopBlock)task{
   [self.tasks addObject:task];
   if (self.tasks.count > 18) {
       [self.tasks removeObjectAtIndex:0];
   }
}

- (void)addRunloopObserver{
   //獲取Runloop
    CFRunLoopRef runloop = CFRunLoopGetCurrent();
   //定義一個(gè)context
   CFRunLoopObserverContext context = {
       0,
       (__bridge void *)(self),
       &CFRetain,
       &CFRelease,
       NULL
   };
   
   //定義觀察者
   static CFRunLoopObserverRef runloopObserver;
   runloopObserver = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting, YES, 0, &callBack, &context);
   
   //添加觀察者
   CFRunLoopAddObserver(runloop, runloopObserver, kCFRunLoopCommonModes);
   
   //C里面 一旦creat new copy
   CFRelease(runloopObserver);
}

void callBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
   ViewController * vc = (__bridge ViewController *)info;
   if(vc.tasks.count == 0){
       return;
   }
   runloopBlock block = vc.tasks.firstObject;
   block();
   [vc.tasks removeObjectAtIndex:0];
}

Runloop Mode

在監(jiān)視與被監(jiān)視中帚豪, Runloop 要處理的事情還挺復(fù)雜的碳竟。為了讓Runloop 能專心處理自己關(guān)心的那部分事情,引入了Runloop Mode 概念志鞍。


image.png

如圖所示瞭亮, Runloop Model 實(shí)際上是Source、Timer 和 Observer 的集合固棚,不同的Model 把不同組的 Source统翩、 Timer 和 Observer 隔絕開來(lái)。Runloop 在某個(gè)時(shí)刻只能跑在一個(gè) Mode 下此洲,處理這一個(gè) Model 種種的 Source厂汗,Timer 和 Observer。
蘋果文檔中提到的 Mode 有五個(gè)呜师,分別是:

  • NSDefaultRunLoopMode
  • NSConnectionReplyModel
  • NSModalPanelRunLoopMode
  • NSEventTrackingRunLoopMode
  • NSRunLoopCommonModes

iOS中公開暴露出來(lái)的只有 NSDefaultRunLoopMode 和 NSRunLoopCommonMode.NSRunLoopCommonMode實(shí)際上是一個(gè)Mode的集合娶桦,默認(rèn)包括 NSDefaultRunLoopMode 和 NSEventTrackingRunLoopMode

與 RunLoop 相關(guān)的坑

日常開發(fā)中,與 runloop 接觸最近的可能就是NSTimerle汁汗。一個(gè) Timer一次只能加入到一個(gè) RunLoop中衷畦。我們?nèi)粘J褂玫臅r(shí)候,通常就是加入到當(dāng)前的runLoop的default model中知牌,而ScrollView 在用戶滑動(dòng)的時(shí)候祈争,主線程RunLoop會(huì)轉(zhuǎn)到NSTrackingRunLoopMode。er這個(gè)時(shí)候角寸,Timer就不會(huì)運(yùn)行菩混。
有如下兩種解決方案:

  • 第一種:設(shè)置RunLoop Mode忿墅,例如NSTimer,我們指定它
    運(yùn)行于NSRunLoopCommonModes沮峡,這是一個(gè)Mode的集
    合疚脐。注冊(cè)到這個(gè)Mode下后,無(wú)論當(dāng)前runLoop運(yùn)行哪個(gè)
    mode邢疙,時(shí)間都能得到執(zhí)行棍弄。
  • 第二種:另一種解決Timer的方法是,我們?cè)诹硪粋€(gè)線程執(zhí)行和處理Timer事件秘症,然后在主線程更新UI照卦。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市乡摹,隨后出現(xiàn)的幾起案子役耕,更是在濱河造成了極大的恐慌,老刑警劉巖聪廉,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞬痘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡板熊,警方通過(guò)查閱死者的電腦和手機(jī)框全,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)干签,“玉大人津辩,你說(shuō)我怎么就攤上這事∪堇停” “怎么了喘沿?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)竭贩。 經(jīng)常有香客問(wèn)我蚜印,道長(zhǎng),這世上最難降的妖魔是什么留量? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任窄赋,我火速辦了婚禮,結(jié)果婚禮上楼熄,老公的妹妹穿的比我還像新娘忆绰。我一直安慰自己,他們只是感情好可岂,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布错敢。 她就那樣靜靜地躺著,像睡著了一般青柄。 火紅的嫁衣襯著肌膚如雪伐债。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天致开,我揣著相機(jī)與錄音峰锁,去河邊找鬼。 笑死双戳,一個(gè)胖子當(dāng)著我的面吹牛虹蒋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播飒货,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼魄衅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了塘辅?” 一聲冷哼從身側(cè)響起晃虫,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扣墩,沒(méi)想到半個(gè)月后哲银,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡呻惕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年荆责,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亚脆。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡做院,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出濒持,到底是詐尸還是另有隱情键耕,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布弥喉,位于F島的核電站郁竟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏由境。R本人自食惡果不足惜棚亩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望虏杰。 院中可真熱鬧讥蟆,春花似錦、人聲如沸纺阔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)笛钝。三九已至质况,卻和暖如春愕宋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背结榄。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工中贝, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人臼朗。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓邻寿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親视哑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绣否,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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