iOS runloop

寫這篇文章開始之前,我都不知道runloop是什么東西,如果從字面的意思翻譯應(yīng)該是一直循環(huán)的跑,懷疑可能和死鎖有關(guān)系,可是死鎖具體是怎么回事,我只是記得有這個說法,也發(fā)現(xiàn)了一個自己不懂的知識。

初識runloop

我在網(wǎng)上看了一下@sunnnyxx 關(guān)于runloop的視頻.了解了一下runloop相關(guān)知識,也去網(wǎng)絡(luò)上看各種關(guān)于runloop的講述。

我們一般程序就是執(zhí)行一個線程,是一條直線.有起點終點.而runloop就是一直在線程上面畫圓圈,一直在跑圈,除非切斷否則一直在運行。網(wǎng)上說的比喻很好,直線就像曇花一現(xiàn)一樣,圓就像OS,一直運行直到你關(guān)機為止。

在我們學(xué)習(xí)iOS生命周期里面都會存在銷毀的過程,但是屏幕好像一直能接收各種指令,感覺很像runloop的功效,好像這些是和頂層UIKit無關(guān),IOS架構(gòu)最底層是Core OS,我分析應(yīng)該是蘋果封裝好了,只是我們看不到源碼而已。


為什么要使用runloop

@sunnnyxx 在視頻介紹了四個作用:

  • 使程序一直運行接受用戶輸入
  • 決定程序在何時應(yīng)該處理哪些Event
  • 調(diào)用解耦(對于編程經(jīng)驗為0的完全沒搞懂這個意思,解釋為Message Queue)
  • 節(jié)省CPU時間

這段視頻我覺得不太適合小白去看,因為好多概念還沒有融會貫通,也沒有理解透徹。但是既然看了,就得總結(jié)一下,至少產(chǎn)生一個樹突先,留下一個問號,未來把問號變成嘆號。

回到開始的疑問,為什么要使用RunLoop,一般情況下我們是沒必要去啟動線程的RunLoop,除非需要在一個單獨的線程長久的檢測某個事件,就像視頻里面提到的類似微信的語音功能,見一個RunLoop專門負(fù)責(zé)監(jiān)聽說話的線程。看需求而定了。


CFRunLoopSource

Source是RunLoop的數(shù)據(jù)源抽象類,類似IOS中的protocol

RunLoop定義兩個Version的Source

  • Source0:處理App內(nèi)部事件,App自己負(fù)責(zé)管理(觸發(fā)),如UIEvent,CFSocket
  • Source1:由RunLoop和內(nèi)核管理,Mach port驅(qū)動 如CFMach、CFMessage

CFRunLoopObserver

向內(nèi)部報告RunLoop當(dāng)前狀態(tài)的更改 CAAnimation

RunLoopObserver 與 Autorelease Pool

UIKit通過RunLoopObserver在RunLoop兩次Sleep間對AutoreleasePool進(jìn)行pop和push,將這次Loop中產(chǎn)生的Autorelease對象釋放。(好像swift中沒有關(guān)于釋放的問題)

CFRunLoopMode

RunLoop在同一時段只能且必須在一種特定Mode下Run
更換Mode時, 需要暫停當(dāng)前的Loop,然后重啟新的Loop

  • NSDefalutRunLoopMode? ? ? 默認(rèn)狀態(tài).空閑狀態(tài)
  • UITrackingRunLoopMode? ? ?滑動ScrollView
  • UIInitializationRunLoopMode? ? 私有,App啟動時
  • NSRunLoopCommonModes? ? ?默認(rèn)包括上面第一和第二

UITrackingRunLoopMode 與 NSTimer

默認(rèn)情況下NSTimer被加入NSDefalutRunLoopMode
如果想NSTimer受到組件或者動畫影響 添加到NSRunLoopCommonModes(OC代碼如下:)

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

swift版代碼:

 NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)

RunLoopMode切換

NSDefaultRunLoopMode->UITrackingRunLoopMode->NSDefalutRunLoopMode

RunLoop的掛起與喚醒

  • 制定用于喚醒的mach_port端口
  • 調(diào)用mach_msg監(jiān)聽喚醒端口,被喚醒前,系統(tǒng)內(nèi)核將這個線程掛起,停留在mach_msg_trap
  • 由另外一個線程(或另一個進(jìn)程中的某個線程)向內(nèi)核發(fā)送這個端口的msg后,trap狀態(tài)被喚醒,RunLoop繼續(xù)開始干活

AFNetWorking 中創(chuàng)建RunLoop

創(chuàng)建一個常駐服務(wù)線程的很好方法

 [[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefalutRunLoopMode]//一直活著
[runLoop run];

swift版代碼

var loop = NSRunLoop.currentRunLoop()
loop.addPort(NSMachPort(), forMode: NSDefaultRunLoopMode)
loop.run()

一個TableView延遲加載圖片的新思路

[self.avatarImageView performSelector:@selector(serImage:)  
                        withObjetc:downloadedImage
                        afterDelay:0
                        inModes:@[NSDefaultRunLoopMode]]
 + (NSThread *)networkRequestThread {
      static NSThread *_networkRequestThread = nil;
      static dispatch_once_t oncePredicate;
      dispatch_once(&oncePredicate, ^{
      _networkRequestThread =
      [[NSThread alloc] initWithTarget:self
           selector:@selector(networkRequestThreadEntryPoint:)
           object:nil];
      [_networkRequestThread start];
 });

 return _networkRequestThread;

}
這個代碼無法轉(zhuǎn)換成swift,可能是我沒想到辦法,大家誰找到了請評論,謝謝了。


讓Crash的App回光返照 只針對Signal Crash

CFRunLoopRef runloop = CFRunLoopGetCurrent();
NSArray *allModes = CFBridgingRelease(CFRunLoopCopyAllModes(runLoop));
while(1){
    for (NSString *mode in allModes){
        CFRunLoopInMode((CFStringRef)mode,0.001,false);
    }
}

RunLoop事件隊列
每次運行run loop,你線程的run loop對會自動處理之前未處理的消息,并通知相關(guān)的觀察者。具體的順序如下:

  1. 通知觀察者run loop已經(jīng)啟動
  2. 通知觀察者任何即將要開始的定時器
  3. 通知觀察者任何即將啟動的非基于端口的源
  4. 啟動任何準(zhǔn)備好的非基于端口的源
  5. 如果基于端口的源準(zhǔn)備好并處于等待狀態(tài),立即啟動;并進(jìn)入步驟9。
  6. 通知觀察者線程進(jìn)入休眠
  7. 將線程置于休眠直到任一下面的事件發(fā)生:
  • 某一事件到達(dá)基于端口的源
  • 定時器啟動
  • Run loop設(shè)置的時間已經(jīng)超時
  • run loop被顯式喚醒
  1. 通知觀察者線程將被喚醒。
  2. 處理未處理的事件
  • 如果用戶定義的定時器啟動,處理定時器事件并重啟run loop。進(jìn)入步驟2
  • 如果輸入源啟動,傳遞相應(yīng)的消息
  • 如果run loop被顯式喚醒而且時間還沒超時,重啟run loop。進(jìn)入步驟2
  1. 通知觀察者run loop結(jié)束。

異步測試

- (BOOL)runUntilBlock:(BOOL(^)())block timeout:(NSTimeInterval)timeout{   
      __block Boolean fulfilled = NO;
      void (^beforeWaiting) (CFRunLoopObserverRef observer, CFRunLoopActivity activity) =
 ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
      fulfilled = block();
      if (fulfilled) {
           CFRunLoopStop(CFRunLoopGetCurrent());
      }
 };

 CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, beforeWaiting);
 CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

 // Run!
 CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, false);

 CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
 CFRelease(observer);

 return fulfilled;

}


總結(jié)一下

基本上對于RunLoop,我只能說我只有簡單的模糊印象,但是不理解,也不太清楚在現(xiàn)實如何使用,因為實踐才能知道如何做,真的在腦里形成了樹突,希望在未來搞定,研究透徹。看這些代碼時候我發(fā)現(xiàn)我的基礎(chǔ)知識還需要鞏固。感謝不相識的孫源。
聲明一點:不要只去收藏,去看看代碼有沒有問題,知識有沒有解釋錯誤的,交流學(xué)的更快。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,844評論 2 372

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