? ? ? ? 關(guān)于Run Loops看了很多大神文章,還是有點(diǎn)云里霧里,所以有時(shí)間感覺還是有必要從概念入手,仔細(xì)啃一遍官方文檔。一起學(xué)習(xí)理解,有錯(cuò)誤的地方請(qǐng)指正。
RunLoop-概念
? ? ??Run Loops是一個(gè)事件處理循環(huán)機(jī)制,用于整合處理接收到的事件,它是IOS與線程相關(guān)的基礎(chǔ)架構(gòu)的一部分。Run Loops的主要職責(zé)是當(dāng)有事件需要處理的時(shí)候喚醒線程進(jìn)行處理,反之使線程處于休眠狀態(tài)。
? ? ? 每個(gè)線程都有一個(gè)相關(guān)聯(lián)的Run Loops對(duì)象,我們的程序不需要自己去創(chuàng)建。?Cocoa and Core Foundation都提供了相應(yīng)的接口幫助我們配置以及管理與線程相關(guān)聯(lián)的Run Loops,主線程的run loop是隨著程序啟動(dòng)的時(shí)候已經(jīng)自動(dòng)配置和啟動(dòng)的,其他線程的runloop需要我們自己手動(dòng)啟用。CFRunLoop 是Core Foundation 庫提供的runloop接口用C/C++實(shí)現(xiàn)的,是線程安全的,NSRunLoop是Foundation提供的接口用OC實(shí)現(xiàn),是對(duì)CFRunLoop的封裝,不是線程安全的,所以我們用NSRunLoop的對(duì)象處理runloop的時(shí)候需要避免在多線程處理。
RunLoop-原理
? ? ? ?Run Loops是一個(gè)循環(huán),線程啟動(dòng),借助runloop響應(yīng)處理輸入的事件,runloop的本質(zhì)就是借助while或者for控制語句實(shí)現(xiàn)的,在循環(huán)里面我們使用run loop 的對(duì)象接收事件以及執(zhí)行處理操作。
? ? ? ? Run Loops接收兩種不同的事件源,Input sources和Timer sources。Input sources發(fā)送異步事件,比如線程之間的通信或者APP之間的通信。Timer sources發(fā)送同步事件,比如在預(yù)定的時(shí)間發(fā)生的事件或者重復(fù)發(fā)生的事件。對(duì)于Input sources我們可以通過Core Foundation 框架提供的接口注冊(cè)runloop的觀察者,當(dāng)runloop的行為發(fā)生改變我們可以收到通知,以此做一些需要的操作。runloop處理這兩種事件源都是按照程序指定的流程處理,如圖所示:

RunLoop-模式
? ? ? ?runloop模式是Input?sources和Timer sources事件集合以及注冊(cè)觀察runloop的觀察者集合。我們運(yùn)行runloop都需要指定對(duì)應(yīng)的模式,當(dāng)我們指定某種模式,只有該模式相關(guān)聯(lián)的事件源會(huì)被監(jiān)聽并且允許其傳遞事件(類似的只有觀察了對(duì)應(yīng)模式的runloop才會(huì)收到,runloop的處理進(jìn)度)。其他模式的事件源只能等待適合的模式才能向runloop傳遞事件。Core Foundation框架提供了五種模式(NSDefaultRunLoopMode,NSConnectionReplyMode,NSModalPanelRunLoopMode,NSEventTrackingRunLoopMode,NSRunLoopCommonModes),我們這里只介紹三種常用的,如果有需要下次再更新。
1.NSDefaultRunLoopMode:默認(rèn)模式,大多數(shù)時(shí)候我們使用這個(gè)模式啟動(dòng)runloop和配置input sources,比如我們創(chuàng)建的定時(shí)器默認(rèn)就是該模式。
2.NSEventTrackingRunLoopMode:字面意思就是事件追蹤模式,該模式監(jiān)聽鼠標(biāo)拖動(dòng)(手指拖動(dòng))以及其他類型的用戶交互追蹤。比如當(dāng)我們滑動(dòng)表的時(shí)候就會(huì)觸發(fā)該模式下的runloop。
3.NSRunLoopCommonModes:這個(gè)模式是一個(gè)常用模式的組合,在Foundation框架下該模式包含NSDefaultRunLoopMode和NSEventTrackingRunLoopMode,在Core Foundation下只包含NSDefaultRunLoopMode,我們可以使用CFRunLoopAddCommonMode函數(shù)將自定義模式添加到該集合。指定這種模式就相當(dāng)于指定了該模式組合下的所有模式。
我們何時(shí)需要使用RunLoop?
? ?你可能用到runloop的地方是當(dāng)你創(chuàng)建子線程的時(shí)候,但是并不是所有的子線程都需要開啟runloop,比如你開始一個(gè)子線程執(zhí)行一個(gè)復(fù)雜耗時(shí)的任務(wù)或者一個(gè)預(yù)先設(shè)定好的任務(wù),此時(shí)我們都不需要開啟runloop,很多時(shí)候runloop是用于線程間的通訊的。官方總結(jié)了以下幾點(diǎn)我們會(huì)使用到runloop的地方:
1.當(dāng)我們使用端口或者自定義的input sources與其他線程交互的時(shí)候。
2.在線程中使用定時(shí)器。
3.在程序中使用任何的performSelector… 方法。
4.讓線程執(zhí)行定期的任務(wù)
RunLoop使用注意事項(xiàng)
? ? ? ? 開啟runloop有三種方法,1.不加任何限制的開啟,2設(shè)定一個(gè)限定時(shí)間,3.指定一種模式。一個(gè)runloop至少需要監(jiān)視一個(gè)input source或者一個(gè)定時(shí)器,否則runloop會(huì)立即退出。第一種開啟的方法是最簡(jiǎn)單的但是也是最不可取的,因?yàn)檫@種方法是不可控制。第二種方法和第三種方法可以混合使用,而且是比較推薦使用的。
? ? ? ?退出runloop有兩種方式:1.當(dāng)我們以限定時(shí)間開啟一個(gè)runloop時(shí),時(shí)間結(jié)束,runloop就會(huì)退出,2.手動(dòng)停止,調(diào)用Core Foundation提供的CFRunLoopStop函數(shù)。雖然移除input source或者定時(shí)器會(huì)使runloop退出,但是很多時(shí)候,我們的代碼不能正真的移除input source或者定時(shí)器,而這些會(huì)阻止runloop退出。