RunLoop

What's Run Loops?
其實就是跑圈的意思枚尼,就像下面這張圖

RunLoop

那么RunLoop具體解決什么問題呢庭惜?
首先看一下下面普通的代碼院峡,就是寫一個 Hello world

int main(int argc, char *argc[]) {
       NSLog(@"Hello world");
       return 0;
}

上面的代碼呢是從 main 函數(shù)開始執(zhí)行窖式, 到return 0 之后就在查看日志的地方打印一行 Hello world港柜。然后就退出了刘陶, 它是一個命令式線性執(zhí)行的一個過程胳赌。
** 但是咱們的手機應(yīng)用肯定不能說上來執(zhí)行完代碼之后就完了,結(jié)束了匙隔。它得一直去保持接收用戶消息疑苫、或者處理一些什么事情啊的這么一個狀態(tài),它必須一直去活著纷责。等到用戶把它干掉才能退出捍掺。**



那咱們再來一段偽代碼:

int main(int argc, char *argc[]) {
        while (AppIsRunning) {
              id whoWakesMe = SleepForWakingUp();
              id event = GetEvent(whoWakesMe);
              HandleEvent(event);
        }      
}

上面的代碼可以歸納為 event 驅(qū)動,即咱們手機是一個事件驅(qū)動的這么一個架構(gòu)再膳。要實現(xiàn)這個event驅(qū)動的方法是挺勿,它的主體是一個死循環(huán)就行了。while這個程序還在跑喂柒,如果沒事的話不瓶,它就去睡覺,假如有事灾杰,有人把它喚醒蚊丐,去取一下是什么事件把它喚醒,然后去分配這個事件艳吠,去執(zhí)行就ok了麦备。


好了, 現(xiàn)在總結(jié)一下昭娩, 為什么要有這個RunLoop呢凛篙?

  1. 必須要讓這個程序一直活著,使程序一直運行并接受用戶輸入或者網(wǎng)絡(luò)的輸入栏渺,程序自己還得有輸出呛梆,必須要一直保持和用戶交互的這么一個狀態(tài)
  2. 決定程序在何時應(yīng)該處理那些Event
  3. 調(diào)用解耦(Message Queue)
那么什么是解耦呢?
主調(diào)方(也就是用戶或者其他)把Event扔到消息隊列里迈嘹,不管了.
然后被調(diào)方(處理UI事件的這一方)每一次去消息隊列里取event削彬,取完之后是自己出派發(fā)呀或者是執(zhí)行某些代碼.
跟主調(diào)方可以實現(xiàn)一個解耦.
  1. 節(jié)省CPU時間
下面我們來看一下RunLoop構(gòu)成元素

從圖中可以看到全庸, RunLoop 和 線程(Thread)是一一對應(yīng)的關(guān)系秀仲。
其他的對應(yīng)關(guān)系也就可以看明白了融痛。

  • CFRunLoopTimer
    咱們平時用到的一些關(guān)于time的方法都是關(guān)于RunLoopTimer的封裝
  • CFRunLoopSource
    Source 是RunLoop的數(shù)據(jù)源抽象類(protocol)
    1 Source0: 處理App內(nèi)部事件,App自己負責管理(觸發(fā))如UIEvent、CFSocket
    2 Source1: 由RunLoop和內(nèi)核管理, Mach port 驅(qū)動,如CFMessagePort
    如果有需要, 可以從中選擇一種自己的Source
    上一條基本不會發(fā)生
  • CFRunLoopObserver
    向外部報告RunLoop當前狀態(tài)的更改
    框架中很多機制都由RunLoopObserver觸發(fā), 如CAAnimation

RunLoopObserver 與 AutoreleasePool的關(guān)系:
UIKit通過在 RunLoop兩次Sleep間對AutoreleasePool進行Pop和Push將這次Loop中產(chǎn)生Autorelease對象釋放

  • CFRunLoopMode
    RunLoop在同一段時間只能且必須在一種特定Mode下Run
    更換Mode時,需要停止當前Loop, 然后重啟新Loop
    Mode是iOS App滑動順暢的關(guān)鍵
    可以定制自己的mode(當然這一點通常情況下也是不會發(fā)生的)
    1 NSDefaultRunLoopMode 默認狀態(tài)神僵,空閑狀態(tài)
    2 UITrackingRunLoopMode 滑動ScrollView時
    3 UIInitializationRunLoopMode 私有App啟動時執(zhí)行
    4 NSRunLoopCommonModes 在這個Mode下, 1和2都可以執(zhí)行是Mode 集合

** RunLoop與dispatch_get_main_queue()的關(guān)系:**
GCD中diapatch到main queue的block被分到main RunLoop執(zhí)行
dispatch_after同理

  • RunLoop的掛起和喚醒
    1 等待的時候先指定用于喚醒的 mach_port端口雁刷,然后可以睡覺了
    2 調(diào)用mach_msg 監(jiān)聽喚醒端口,被喚醒前,系統(tǒng)內(nèi)核將這個線程掛起,停留在mach_msg_trap狀態(tài)
    3 由另一個線程(或另一個進程中的某個線程)向內(nèi)核發(fā)送這個端口msg后,trap狀態(tài)被喚醒,RunLoop繼續(xù)開始干活

** RunLoop迭代執(zhí)行順序**
寫一段偽代碼總結(jié)一下do while里干的事

SetupThisRunLoopTimeOutTimer(); // by GCD timer. do while 之前先得有一個RunLoop的過期時間, 這樣它并不是一個正真的死循環(huán),而是有一個很長很長的time不可能執(zhí)行完保礼。
do {
  __CFRunLoopCoObservers[kCFRunLoopBeforeTimers]; // 告訴observers 我要跑timer了
  __CFRunLoopDoObservers[kCFRunLoopBeforeSources]; // 告訴observers 我要跑 source了
  __CFRunLoopDoBlocks();  // 跑哪6個其中一個
  __CFRunLoopDoSource0(); // 跑source0
// 跑到這的時候沛励,程序先向source0中看一下在消息列隊中有沒有什么可以分派或者執(zhí)行的消息
// 如果有,這個里面會遍歷source0去跑
  CheckIfExistMessagesInMainDispatchQueue(); // 然后去問一下GCD你有沒有分到主線程的東西需要我?guī)湍阏{(diào)
  __CFRunLoopDoObservers[kCFRunLoopBeforeWaiting]; // 開始睡覺
  var wakeUpPort = SleepAndWaitingForWakingUpPorts(); // 知道是哪個端口把我喚醒的
  __CFRunLoopDoObservers[kCFRunLoopAfterWaiting]; // 醒來之后告訴Observer 是哪個端口喚醒我的
  if (waitingUpPort == timePort) { // 如果是timer把我喚醒的就去跑timer的事件
    __CFRunLoopDoTimers();
  } else if (wakeUpPort == mainDispatchQueue) { // 如果是主線程的GCD把你喚醒的炮障,就去幫GCD干事了
 __CFRunLoop_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE_();
  } else { // 如果都不是的話目派,那就跑source1,source1是基于port事件胁赢。
    __CFRunLoopDoSource1();
  }
  __CFRunLoopDoBlacks();
// 這就是一圈RunLoop要跑的代碼
} while (!stop && !timeout);

OK.


文后一笑
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末企蹭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子智末,更是在濱河造成了極大的恐慌谅摄,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件系馆,死亡現(xiàn)場離奇詭異送漠,居然都是意外死亡,警方通過查閱死者的電腦和手機由蘑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門闽寡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人尼酿,你說我怎么就攤上這事下隧。” “怎么了谓媒?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵淆院,是天一觀的道長。 經(jīng)常有香客問我句惯,道長土辩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任抢野,我火速辦了婚禮拷淘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘指孤。我一直安慰自己启涯,他們只是感情好贬堵,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著结洼,像睡著了一般黎做。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上松忍,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天蒸殿,我揣著相機與錄音,去河邊找鬼鸣峭。 笑死宏所,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的摊溶。 我是一名探鬼主播爬骤,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼莫换!你這毒婦竟也來了霞玄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤浓镜,失蹤者是張志新(化名)和其女友劉穎溃列,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膛薛,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡听隐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哄啄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雅任。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖咨跌,靈堂內(nèi)的尸體忽然破棺而出沪么,到底是詐尸還是另有隱情,我是刑警寧澤锌半,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布禽车,位于F島的核電站,受9級特大地震影響刊殉,放射性物質(zhì)發(fā)生泄漏殉摔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一记焊、第九天 我趴在偏房一處隱蔽的房頂上張望逸月。 院中可真熱鬧,春花似錦遍膜、人聲如沸碗硬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恩尾。三九已至弛说,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間特笋,已是汗流浹背剃浇。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工巾兆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留猎物,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓角塑,卻偏偏與公主長得像蔫磨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子圃伶,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

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