iOS基礎-Runloop

Runloop

[TOC]

一覆旱、概念

Runloop就是一個事件處理的循環(huán)缕探,用來不停的調(diào)度工作及處理輸入事件Runloop是事件接收和分發(fā)機制的一個實現(xiàn)找爱。是線程相關的基礎框架的一部分绍坝。

實例:main 函數(shù)(有無循環(huán)對比)
問題:UIApplicationMain做了什么碰辅?

// 偽代碼
int main(int argc, char * argv[]) {
    @autoreleasepool {
        int retVal = 0;
        do {
            // 睡眠中等待消息
            int message = sleep_and_wait();
            // 處理消息
            retVal = process_message(retVal);
        } while (0 == retVal);
    }
    return 0;
}
基本作用
  1. 保持程序的持續(xù)運行采郎。
  2. 處理app的各種事件千所。如:觸摸事件、定時器事件等蒜埋。
  3. 節(jié)省CPU資源淫痰,提高程序性能。Runloop并不是由系統(tǒng)自動控制的整份,需要檢測是否有需要處理的事件待错。如果有則去處理,如果沒有則進入睡眠以節(jié)省CPU烈评。
Runloop 是一個對象

iOS中有兩套API訪問Runloop對象:
Foundation框架:NSRunloop
Core Foundation:CFRunloopRef
NSRunloop是基于CFRunloopRef的一層OC包裝火俄,兩者皆是Runloop對象。

Runloop 與線程
  1. 每個線程都有且僅有一個與之對應的Runloop對象讲冠。
  2. Runloop 保存在一個全局的 Dictionary 中烛占,線程為 key,線程對應的 Runloop 為 value沟启。
  3. 線程剛創(chuàng)建的時候是沒有Runloop對象的忆家,Runloop會在第一次獲取時創(chuàng)建(懶加載)。
  4. 主線程默認創(chuàng)建Runloop德迹,子線程默認不開啟芽卿。
    主線程在創(chuàng)建時也是沒有 runloop 對象的,而是 UIApplicationMain 方法里創(chuàng)建胳搞。
  5. Runloop 在線程結(jié)束時銷毀卸例。

獲取 Runloop 對象

    // 獲取當前線程的 Runloop 對象
    NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
    CFRunLoopRef currentRunloopRef = CFRunLoopGetCurrent();
    // 獲取主線程的 Runloop 對象
    NSRunLoop *mainRunloop = [NSRunLoop mainRunLoop];
    CFRunLoopRef mainRunloopRef = CFRunLoopGetMain();
    
    /**
    問題:內(nèi)存地址不一致称杨?
    NSRunLoop對象 包含 CFRunLoopRef對象。
    */

源碼:CFRunLoop.c

二筷转、API

Core Foundation中關于RunLoop的5個類
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef

typedef struct __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop {
    pthread_t _pthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
};

typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
    CFStringRef _name;
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
};
image.png
CFRunLoopModeRef
  1. CFRunLoopModeRef 代表 Runloop 的運行模式姑原。
  2. 一個 Runloop 包含多個 Mode,每個 Mode 又包含若干個 Source0/Source1/Timer/Observer呜舒。
    不同組的 Source0/Source1/Timer/Observer 能分隔開來锭汛,互不影響。(實例:CommonMode)
    如果Mode里沒有任何Source0/Source1/Timer/Observer袭蝗,RunLoop會立馬退出唤殴。
  3. Runloop 啟動時只能選擇其中一個 Mode,作為 currentMode到腥。
  4. 如果需要切換 Mode朵逝,只能退出當前 loop,再重新選擇一個 Mode 進入乡范。

目前已知的 Mode有5種

  • kCFRunLoopDefaultMode:App的默認Mode配名,通常主線程是在這個Mode下運行。
  • UITrackingRunLoopMode:界面跟蹤 Mode晋辆,用于 ScrollView 追蹤觸摸滑動段誊,保證界面滑動時不受其他 Mode 影響。
  • UIInitializationRunLoopMode:在剛啟動 App 時第進入的第一個 Mode栈拖,啟動完成后就不再使用连舍。
  • GSEventReceiveRunLoopMode:接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到涩哟。
  • kCFRunLoopCommonModes:這是一個占位用的Mode索赏,不是一種真正的Mode。

Mode屬性的基本概念

  1. Source0:

    • 觸摸事件 (Line source0Demo)
    • performSelector:onThread:
  2. Source1:

    • 基于port的線程通信
    • 系統(tǒng)事件捕捉
  3. Timers:

    • NSTimer
    • performSelector:withObject:afterDelay:
  4. Observers:

    • 用于監(jiān)聽 Runloop 的狀態(tài)
    • UI刷新(BeforeWaiting)
    • Autoreleasetool(BeforeWaiting)

以上即為 Runloop 處理的事件贴彼。
Runloop響應用戶操作:Source1捕捉用戶操作潜腻,分發(fā)給Source0進行處理。

三器仗、Runloop 的運行邏輯

Runloop 狀態(tài)
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0), //即將進入 loop
    kCFRunLoopBeforeTimers = (1UL << 1), //即將處理Timer
    kCFRunLoopBeforeSources = (1UL << 2), //即將處理Source
    kCFRunLoopBeforeWaiting = (1UL << 5), //即將進入休眠
    kCFRunLoopAfterWaiting = (1UL << 6), //剛從休眠中喚醒
    kCFRunLoopExit = (1UL << 7), //即將退出 loop
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

可以往 RunLoop 中加入自己的觀察者以便監(jiān)控著 RunLoop 的運行過程融涣。
示例:

  1. 監(jiān)聽 Runloop 狀態(tài) (Line observeRunloopStatus)
    • 創(chuàng)建監(jiān)聽器
    • 將監(jiān)聽器加入 Runloop
    • 監(jiān)聽回調(diào)
  2. NSTimer
  3. 滾動模式與默認模式的切換
Runloop 的運行流程
1. 通知Observers:進入Loop
2. 通知Observers:即將處理Timers
3. 通知Observers:即將處理Sources
4. 處理Blocks
5. 處理Source0(可能會再次處理Blocks)
6. 如果存在Source1,就跳轉(zhuǎn)到第8步
7. 通知Observers:開始休眠(等待消息喚醒)
8. 通知Observers:結(jié)束休眠(被某個消息喚醒)
    1. 處理Timer
    2. 處理GCD Async To Main Queue
    3. 處理Source1
9. 處理Blocks
10. 根據(jù)前面的執(zhí)行結(jié)果精钮,決定如何操作
    1. 回到第02步
    2. 退出Loop
11. 通知Observers:退出Loop

實例:
1. touch 事件堆棧
2. GCD Async To Main Queue (Line gcdMainQueue)
源碼:CFRunLoopRunSpecific

休眠狀態(tài):內(nèi)核休眠威鹿,CPU不分配資源,線程睡眠狀態(tài)轨香。

四忽你、應用

  1. 控制線程生命周期(線程保活)(Line source0Demo)
  2. 解決NSTimer在滑動時停止工作的問題(commonModes)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末臂容,一起剝皮案震驚了整個濱河市科雳,隨后出現(xiàn)的幾起案子根蟹,更是在濱河造成了極大的恐慌,老刑警劉巖糟秘,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件简逮,死亡現(xiàn)場離奇詭異,居然都是意外死亡尿赚,警方通過查閱死者的電腦和手機散庶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吼畏,“玉大人督赤,你說我怎么就攤上這事嘁灯⌒何茫” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵丑婿,是天一觀的道長性雄。 經(jīng)常有香客問我,道長羹奉,這世上最難降的妖魔是什么秒旋? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮诀拭,結(jié)果婚禮上迁筛,老公的妹妹穿的比我還像新娘。我一直安慰自己耕挨,他們只是感情好细卧,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著筒占,像睡著了一般贪庙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翰苫,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天止邮,我揣著相機與錄音,去河邊找鬼奏窑。 笑死导披,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的埃唯。 我是一名探鬼主播盛卡,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼筑凫!你這毒婦竟也來了滑沧?” 一聲冷哼從身側(cè)響起并村,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎滓技,沒想到半個月后哩牍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡令漂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年膝昆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叠必。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡荚孵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纬朝,到底是詐尸還是另有隱情收叶,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布共苛,位于F島的核電站判没,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏隅茎。R本人自食惡果不足惜澄峰,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辟犀。 院中可真熱鬧俏竞,春花似錦、人聲如沸堂竟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跃捣。三九已至漱牵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疚漆,已是汗流浹背酣胀。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娶聘,地道東北人闻镶。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像丸升,于是被迫代替她去往敵國和親铆农。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345