RunLoop的表層概念

概覽

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

附一個runloop小demo:https://github.com/AnduinWrynnK/Diablos

RunLoop的外形


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

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

RunLoop的設(shè)計意義

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

RunLoop的運行原理

基于RunLoop外形,runloop的運行原理是:


原理圖


實現(xiàn)(上)


實現(xiàn)(下)

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

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

RunLoopMode

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

kCFRunLoopDefaultMode

App的默認Mode,通常主線程是在這個Mode下運行

UITrackingRunLoopMode:

界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響

UIInitializationRunLoopMode:

在剛啟動 App 時第進入的第一個 Mode,啟動完成后就不再使用

GSEventReceiveRunLoopMode:

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

kCFRunLoopCommonModes:

這是一個占位用的Mode,作為標記kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一種真正的Mode

context

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

RunLoop的生命周期

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

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

1.nstimer在默認mode下滑動UI時卡頓,換滑動響應(yīng)的model就可以了,或者將timer丟到子線程并保活子線程。

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

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

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

5.后臺用mach-port?;钜粋€線程用來專門做下載。

6.跟面試官對線。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容