iOS-runloop知識(shí)點(diǎn)整理

RunLoop.png

Runloop

通過內(nèi)部維護(hù)事件循環(huán)來對(duì)事件/消息進(jìn)行管理的一個(gè)對(duì)象赶诊。 沒有消息處理時(shí)舔痪,進(jìn)入休眠以避免資源占用 有消息時(shí),立刻被喚醒


904629-1c7712439e0c4135.png

事件循環(huán)(Event Loop) 事件循環(huán)對(duì)消息進(jìn)行管理夺英,管理狀態(tài)的切換 沒有消息時(shí): 用戶態(tài) ----> 內(nèi)核態(tài) 有消息時(shí):用戶態(tài) <---- 內(nèi)核態(tài)

main函數(shù)為什么不會(huì)退出痛悯? 因?yàn)檎{(diào)用UIApplicationMain啟動(dòng)了一個(gè)Runloop载萌。有接收消息進(jìn)行處理,沒有消息進(jìn)入等待垮衷。

NSRunLoop是CFRunLoop的封裝乖坠,提供面向?qū)ο蟮腁PI熊泵。

CFRunLoop分析

查看蘋果源碼,CFRunLoop結(jié)構(gòu)體如下:

1363078-0e84d5a6c8cc772f.png
  • pthread : 與線程相關(guān)轩勘,一一對(duì)應(yīng)绊寻。

  • currentMode:當(dāng)前RunLoop所處的模式

  • modes 集合CFMutableSetRef

  • commonModes: CFMutableSetRef

  • commonModeItems: 集合悬秉,包含多個(gè)Observer和泌、Timer武氓、Source

CFRunLoopMode

Mode代表RunLoop的不同運(yùn)行模式东羹,運(yùn)行時(shí)只能選擇一種模式運(yùn)行作為currentMode属提,如果想切換需要退出當(dāng)前循環(huán)美尸,重新選擇Mode在進(jìn)入循環(huán)师坎。為什么這樣設(shè)計(jì)呢屹耐,為了隔離開不同的任務(wù)尸疆,互不影響椿猎。

CFRunLoopMode結(jié)構(gòu)體:

1363078-0cff3ff96182087a.png

CFRunLoopModeRef

RunLoopMode中包含的內(nèi)容:

  • name: 名稱NSDefaultRunLoopMode

  • source0:處理點(diǎn)擊事件,performSelector:onThread:withObject:方法寿弱。

  • source1

  • observers 數(shù)組

  • timers 數(shù)組

一個(gè)Mode對(duì)應(yīng)多個(gè)Source/Timer/Observer犯眠。RunLoop只能接受到當(dāng)前Mode中添加的事件。

兩種常用的Mode:

  • kCFRunLoopDefaultMode(NSDefaultRunLoopMode): APP的默認(rèn)Mode症革,通常主線程是這個(gè)模式筐咧。

  • UITrackingRunLoopMode: 界面跟蹤Mode,用戶ScrollView追蹤觸摸滑動(dòng)噪矛,保證界面滑動(dòng)是不受其他Mode的影響量蕊。

注意:NSRunLoopCommonMode不是實(shí)際存在的Mode。是同步Source/Timer/Observer到多個(gè)Mode中的一種技術(shù)方案残炮。

CFRunLoopSource

  • source0: 手動(dòng)喚醒線程脉漏。 觸摸事件舅锄,performSelector:onThread:withObject:方法皇忿。

  • source1 :自動(dòng)喚醒線程桨踪,基于Port的線程間通訊 ,系統(tǒng)事件的捕捉汽纠。

CFRunLoopTimer

基于事件的定時(shí)器,可以與NSTimer進(jìn)行轉(zhuǎn)換絮宁。 performSelector:withObject:afterDelay:

CFRunLoopObserver

 CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
      switch (activity) {
          case kCFRunLoopEntry:
              NSLog(@"KCFRunLoopEntry");
              break;
          case kCFRunLoopBeforeTimers:
              NSLog(@"Timers");
              break;
          case kCFRunLoopBeforeSources:
              NSLog(@"Sources");
              break;
          case kCFRunLoopBeforeWaiting:
              NSLog(@"BeforeWaiting");
              break;
          case kCFRunLoopAfterWaiting:
              NSLog(@"AfterWaiting");
              break;
          case kCFRunLoopExit:
              NSLog(@"Exit");
              break;
          default:
              break;
      }
  });
  CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
  CFRelease(observer);

監(jiān)聽RunLoop狀態(tài)窘游,觀測時(shí)間點(diǎn):

  • kCFRunLoopEntry 進(jìn)入RunLoop

  • kCFRunLoopBeforeTimers 將要處理Timer事件 *kCFRunLoopBeforeSources將要處理Source事件

  • kCFRunLoopBeforeWaiting 將要進(jìn)入休眠狀態(tài),切換用戶態(tài)--->內(nèi)核態(tài)喘批。

  • kCFRunLoopAfterWaiting 喚醒逛拱,內(nèi)核態(tài)--->用戶態(tài)

  • kCFRunLoopExit 退出

自動(dòng)釋放池跟RunLoop的狀態(tài)有關(guān)

一個(gè)RunLoop對(duì)應(yīng)多個(gè)Mode俱两,一個(gè)Mode對(duì)應(yīng)多個(gè)Source/Timer/Observer

事件循環(huán)的實(shí)現(xiàn)機(jī)制

1363078-13acd59cc19e6a0c.png

RunLoop的應(yīng)用

滑動(dòng)TableView的時(shí)候定時(shí)器為什么會(huì)失效筹麸?

因?yàn)榛瑒?dòng)TableView的時(shí)候白指,RunLoop發(fā)生了Mode切換错维。 kCFRunLoopDefaultMode ---> UITrackingRunLoopMode。 解決方法:將Timer添加到RunLoop使用commonMode標(biāo)記設(shè)置宏邮。

 // 這種方式添加定時(shí)器不會(huì)出現(xiàn)飒炎,Timer停止的問題郎汪。
  static int count = 0;
  NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
      NSLog(@"%d", count ++);
  }];
  [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
  // NSRunLoopCommonModes 并不是一個(gè)真的模式,而是一個(gè)標(biāo)記。

如何實(shí)現(xiàn)常駐線程凝危?

經(jīng)常使用子線程時(shí),可以創(chuàng)建一個(gè)常駐子線程,可以節(jié)省系統(tǒng)資源苍匆。下面看創(chuàng)建常駐子線程:

BOOL shouldKeepRunning = YES; // global
- (void)viewDidLoad {
  [super viewDidLoad];
  // LEThread繼承自NSThread重寫dealloc方法统求,打印銷毀信息折剃。
  self.thread = [[LEThread alloc] initWithBlock:^{
      // 用于線程弊喔Γ活,不做具體的任務(wù)挠进。
      // 線程一直在運(yùn)行
      [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
//       [[NSRunLoop currentRunLoop] run]; // 開啟一個(gè)無限的循環(huán)案怯,無法停止。
      NSRunLoop *theRL = [NSRunLoop currentRunLoop];
      while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
      NSLog(@"%s ---end----", __func__);
  }];
  // 啟動(dòng)子線程
  [self.thread start];
}
?
//停止線程
// 停止子線程RunLoop捞魁,該方法需要在子線程中調(diào)用。
- (void)stop {
  shouldKeepRunning = NO; // 標(biāo)志
  CFRunLoopStop(CFRunLoopGetCurrent()); // 釋放當(dāng)前RunLoop昆著。
  NSLog(@"%s", __func__);
}
  1. 為當(dāng)前線程開啟一個(gè)RunLoop。

  2. 向該RunLoop中添加一個(gè)Port/Source等維持RunLoop的事件循環(huán)梧宫。

  3. 啟動(dòng)該RunLoop接谨。

小結(jié)

  • 講講RunLoop摆碉,項(xiàng)目中有用到嗎?

  • runloop內(nèi)部實(shí)現(xiàn)邏輯脓豪?

  • runloop和線程的關(guān)系巷帝?

  • timer 與 runloop 的關(guān)系?

  • 程序中添加每3秒響應(yīng)一次的NSTimer笤闯,當(dāng)拖動(dòng)tableview時(shí)timer可能無法響應(yīng)要怎么解決?

  • runloop 是怎么響應(yīng)用戶操作的捐韩, 具體流程是什么樣的仅政?

  • 說說runLoop的幾種狀態(tài)

  • runloop的mode作用是什么?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末裁良,一起剝皮案震驚了整個(gè)濱河市牧抵,隨后出現(xiàn)的幾起案子笛匙,更是在濱河造成了極大的恐慌,老刑警劉巖犀变,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妹孙,死亡現(xiàn)場離奇詭異,居然都是意外死亡获枝,警方通過查閱死者的電腦和手機(jī)蠢正,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來省店,“玉大人嚣崭,你說我怎么就攤上這事∨嘲” “怎么了雹舀?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長粗俱。 經(jīng)常有香客問我说榆,道長,這世上最難降的妖魔是什么寸认? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任签财,我火速辦了婚禮,結(jié)果婚禮上偏塞,老公的妹妹穿的比我還像新娘唱蒸。我一直安慰自己,他們只是感情好烛愧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布油宜。 她就那樣靜靜地躺著,像睡著了一般怜姿。 火紅的嫁衣襯著肌膚如雪慎冤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天沧卢,我揣著相機(jī)與錄音蚁堤,去河邊找鬼。 笑死但狭,一個(gè)胖子當(dāng)著我的面吹牛披诗,可吹牛的內(nèi)容都是我干的撬即。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼呈队,長吁一口氣:“原來是場噩夢啊……” “哼剥槐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宪摧,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤粒竖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后几于,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蕊苗,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年沿彭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了朽砰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喉刘,死狀恐怖瞧柔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饱搏,我是刑警寧澤非剃,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站推沸,受9級(jí)特大地震影響备绽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鬓催,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一肺素、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宇驾,春花似錦倍靡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至筝尾,卻和暖如春捡需,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背筹淫。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國打工站辉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓饰剥,卻偏偏與公主長得像殊霞,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子汰蓉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

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

  • Runloop是iOS和OSX開發(fā)中非潮炼祝基礎(chǔ)的一個(gè)概念,從概念開始學(xué)習(xí)古沥。 RunLoop的概念 -般說瘸右,一個(gè)線程一...
    小貓仔閱讀 995評(píng)論 0 1
  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20150601/11970.html RunL...
    Gatling閱讀 1,438評(píng)論 0 13
  • 前言 RunLoop是iOS和OSX開發(fā)中非常基礎(chǔ)的一個(gè)概念岩齿,這篇文章將從CFRunLoop的源碼入手,介紹Run...
    暮年古稀ZC閱讀 2,243評(píng)論 1 19
  • 轉(zhuǎn)自bireme苞俘,原地址:https://blog.ibireme.com/2015/05/18/runloop/...
    乜_啊_閱讀 1,374評(píng)論 0 5
  • 5月3日下午吃谣,武安市一景點(diǎn)古武當(dāng)山景區(qū)內(nèi)濃煙滾滾乞封、火光沖天,原來是一座“碧霞寺”及周圍失火岗憋。事故發(fā)生后肃晚,武安市旅游...
    聚焦華夏閱讀 395評(píng)論 1 0