RunLoop的表層概念

概覽

我個(gè)人了解一個(gè)事物的習(xí)慣,先去看的的外形,這可以讓我知道他是一個(gè)什么東西,其次,了解他被設(shè)計(jì)出來的意義,這可以讓我知道他的核心邏輯與服務(wù)目標(biāo)。這樣在我眼里他是什么,要去做什么就能有一個(gè)大概的概念。再?gòu)膬蓚€(gè)方向出發(fā)向中間對(duì)合,挖出他怎樣執(zhí)行目標(biāo),如何實(shí)現(xiàn)邏輯的行動(dòng)思想。就可以將其串聯(lián)起來,有一個(gè)容易理解的印象。

附一個(gè)runloop小demo:https://github.com/AnduinWrynnK/Diablos

RunLoop的外形


cfrunloop及mode結(jié)構(gòu)體

runloop表層實(shí)現(xiàn)為一個(gè)結(jié)構(gòu)體,根據(jù)字面量,內(nèi)部屬性有1.所有加入的mode。2.所有的公開mode。3.所有公開mode的內(nèi)部事件集合。4.當(dāng)前運(yùn)行的mode。

RunLoop的設(shè)計(jì)意義

RunLoop循環(huán)是一個(gè)面向線程的任務(wù)處理機(jī)制,他的核心思想是依附于線程的生命周期,有任務(wù)執(zhí)行,無任務(wù)休眠。達(dá)到一個(gè)在任務(wù)空閑時(shí)節(jié)省CPU資源的目的,同時(shí)也規(guī)定了一次任務(wù)處理循環(huán)的標(biāo)準(zhǔn)動(dòng)作。同時(shí),開發(fā)者可以使用RunLoop循環(huán)來實(shí)現(xiàn)線程間的通信,拿出優(yōu)化解決方案。

RunLoop的運(yùn)行原理

基于RunLoop外形,runloop的運(yùn)行原理是:


原理圖


實(shí)現(xiàn)(上)


實(shí)現(xiàn)(下)

runLoop跟隨線程創(chuàng)建,可以處理source1、source0與Timer類型的事件。進(jìn)入循環(huán)后,依次發(fā)出timer source0的執(zhí)行通知并隨后處理這些任務(wù),再檢查是否有source1的事件,有則直接去處理,處理完重新返回查找source0與Timer類型的事件,沒有則跳過。執(zhí)行完畢后發(fā)出通知線程進(jìn)入休眠,當(dāng)收到新的source1消息或手動(dòng)運(yùn)行循環(huán)時(shí),喚醒線程重復(fù)進(jìn)入循環(huán)后的步驟。當(dāng)runloop中source1、source0與Timer類型的事件全部處理完畢或runloop達(dá)到超時(shí)時(shí)間,runloop退出。

與運(yùn)行原理相關(guān)的概念:

RunLoopMode

runloop是loop->mode->source,三級(jí)結(jié)構(gòu),一個(gè)runloop可以有多個(gè)mode,但是一次只能以一個(gè)mode運(yùn)行,runloop處理mode內(nèi)部的事件或者說與mode類型相同的事件,也只發(fā)送當(dāng)前mode注冊(cè)的通知,并在執(zhí)行完畢時(shí)退出,未運(yùn)行的mode不影響當(dāng)前的runloop活動(dòng)。

kCFRunLoopDefaultMode

App的默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行

UITrackingRunLoopMode:

界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動(dòng),保證界面滑動(dòng)時(shí)不受其他 Mode 影響

UIInitializationRunLoopMode:

在剛啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode,啟動(dòng)完成后就不再使用

GSEventReceiveRunLoopMode:

接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到

kCFRunLoopCommonModes:

這是一個(gè)占位用的Mode,作為標(biāo)記kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一種真正的Mode

context

source、Timer與observer都有上下文對(duì)象,source與timer的上下文主要內(nèi)容是三個(gè)回調(diào)函數(shù)用來在加入循環(huán),執(zhí)行與移出循環(huán)時(shí)回調(diào)。而observer的回調(diào)函數(shù)在構(gòu)建CFRunLoopObserverRef時(shí)傳入,不需在上下文中指出。

RunLoop的生命周期

runLoop的生命周期大致與此線程的生命周期相同,起于在線程內(nèi)獲取runloop,終于線程結(jié)束。CFDictionaryGetValue(loopsDic, thread)用來在全局查找thread對(duì)應(yīng)的runloop,沒有時(shí)會(huì)用_CFRunLoopCreate()方法創(chuàng)建并將之加入字典。只要是沒有超時(shí)且還有未解決的事件,runloop就不會(huì)退出,不過這不能保證他是在喚起狀態(tài),source0與timer加入一個(gè)休眠線程是無法執(zhí)行的,所以我們將一個(gè)事件加入一個(gè)runloop之后可以手動(dòng)喚起他。或者是給他加一個(gè)port(source1)事件來讓他停留在執(zhí)行port檢測(cè)這一步保持他的活躍。

開發(fā)者對(duì)RunLoop的實(shí)際應(yīng)用

1.nstimer在默認(rèn)mode下滑動(dòng)UI時(shí)卡頓,換滑動(dòng)響應(yīng)的model就可以了,或者將timer丟到子線程并?;钭泳€程。

2.在scrollView會(huì)大量加載圖片的情況時(shí),可以在runloop通知里結(jié)局這個(gè)問題,滑動(dòng)時(shí)不加載圖片,或者加一個(gè)緩存數(shù)組,一次循環(huán)只加載一張圖片。

3.通過信號(hào)量與runloopObserver方法結(jié)合監(jiān)聽UI卡頓。

4.在runloop中監(jiān)聽崩潰類型,重新運(yùn)行所有的mode,可以阻止此次崩潰,可是阻止不了第二次。

5.后臺(tái)用mach-port?;钜粋€(gè)線程用來專門做下載。

6.跟面試官對(duì)線。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。