iOS面試題:runloop 的 mode 作用是什么类垦?

在 CoreFoundation 里面關(guān)于 RunLoop 有 5 個(gè)類狈邑,分別對(duì)應(yīng)不同的概念:

  • CFRunLoopRef,對(duì)應(yīng) runloop蚤认。

  • CFRunLoopModeRef米苹,對(duì)應(yīng) runloop mode。CFRunLoopModeRef 類并沒有對(duì)外暴露砰琢,只是通過 CFRunLoopRef 的接口進(jìn)行了封裝

  • CFRunLoopSourceRef蘸嘶,對(duì)應(yīng) source,表示事件產(chǎn)生的地方陪汽。Source 有兩個(gè)版本:Source0 和 Source1训唱。Source0 只包含了一個(gè)回調(diào)(函數(shù)指針),它并不能主動(dòng)觸發(fā)事件挚冤。使用時(shí)况增,你需要先調(diào)用 CFRunLoopSourceSignal(source),將這個(gè) Source 標(biāo)記為待處理训挡,然后手動(dòng)調(diào)用 CFRunLoopWakeUp(runloop) 來喚醒 RunLoop澳骤,讓其處理這個(gè)事件。Source1 包含了一個(gè) mach_port 和一個(gè)回調(diào)(函數(shù)指針)澜薄,被用于通過內(nèi)核和其他線程相互發(fā)送消息为肮。這種 Source 能主動(dòng)喚醒 RunLoop 的線程。

  • CFRunLoopTimerRef肤京,對(duì)應(yīng) timer颊艳,是基于時(shí)間的觸發(fā)器。它和 NSTimer 是 toll-free bridged 的忘分,可以混用棋枕。其包含一個(gè)時(shí)間長(zhǎng)度和一個(gè)回調(diào)(函數(shù)指針)。當(dāng)其加入到 RunLoop 時(shí)饭庞,RunLoop 會(huì)注冊(cè)對(duì)應(yīng)的時(shí)間點(diǎn)戒悠,當(dāng)時(shí)間點(diǎn)到時(shí),RunLoop 會(huì)被喚醒以執(zhí)行那個(gè)回調(diào)舟山。

  • CFRunLoopObserverRef绸狐,對(duì)應(yīng) observer卤恳,表示觀察者。每個(gè) Observer 都包含了一個(gè)回調(diào)(函數(shù)指針)寒矿,當(dāng) RunLoop 的狀態(tài)發(fā)生變化時(shí)突琳,觀察者就能通過回調(diào)接受到這個(gè)變化》啵可以觀測(cè)的時(shí)間點(diǎn)有以下幾個(gè):

  • kCFRunLoopEntry拆融,即將進(jìn)入Loop

  • kCFRunLoopBeforeTimers,即將處理 Timer

  • kCFRunLoopBeforeSources啊终,即將處理 Source

  • kCFRunLoopBeforeWaiting镜豹,即將進(jìn)入休眠

  • kCFRunLoopAfterWaiting,剛從休眠中喚醒

  • kCFRunLoopExit蓝牲,即將退出Loop

上面的 Source/Timer/Observer 被統(tǒng)稱為 mode item趟脂,一個(gè) item 可以被同時(shí)加入多個(gè) mode。但一個(gè) item 被重復(fù)加入同一個(gè) mode 時(shí)是不會(huì)有效果的例衍。如果一個(gè) mode 中一個(gè) item 都沒有昔期,則 RunLoop 會(huì)直接退出,不進(jìn)入循環(huán)佛玄。

這些概念的包含關(guān)系如下圖所示:

線程的運(yùn)行的過程中需要去處理不同情境的不同事件硼一,mode 則是這個(gè)情景的標(biāo)識(shí),告訴當(dāng)前應(yīng)該響應(yīng)哪些事件梦抢。一個(gè) RunLoop 包含若干個(gè) Mode般贼,每個(gè) Mode 又包含若干個(gè) Source/Timer/Observer。每次調(diào)用 RunLoop 的主函數(shù)時(shí)惑申,只能指定其中一個(gè) Mode具伍,這個(gè) Mode 被稱作 CurrentMode。如果需要切換 Mode圈驼,只能退出 Loop,再重新指定一個(gè) Mode 進(jìn)入望几。這樣做主要是為了分隔開不同組的 Source/Timer/Observer绩脆,讓其互不影響。

CFRunLoopMode 和 CFRunLoop 的結(jié)構(gòu)大致如下:

    struct __CFRunLoopMode {
        CFStringRef _name;            // Mode Name, 例如 @"kCFRunLoopDefaultMode"
        CFMutableSetRef _sources0;    // Set
        CFMutableSetRef _sources1;    // Set
        CFMutableArrayRef _observers; // Array
        CFMutableArrayRef _timers;    // Array
        ...
    };
     
    struct __CFRunLoop {
        CFMutableSetRef _commonModes;     // Set
        CFMutableSetRef _commonModeItems; // Set<Source/Observer/Timer>
        CFRunLoopModeRef _currentMode;    // Current Runloop Mode
        CFMutableSetRef _modes;           // Set
        ...
    };

這里有個(gè)概念叫 CommonModes:一個(gè) Mode 可以將自己標(biāo)記為 Common 屬性(通過將其 ModeName 添加到 RunLoop 的 commonModes 中)橄抹。每當(dāng) RunLoop 的內(nèi)容發(fā)生變化時(shí)靴迫,RunLoop 都會(huì)自動(dòng)將 _commonModeItems里的 Source/Observer/Timer 同步到具有 Common 標(biāo)記的所有 Mode 里。

應(yīng)用場(chǎng)景舉例:主線程的 RunLoop 里有兩個(gè)預(yù)置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode楼誓。這兩個(gè) Mode 都已經(jīng)被標(biāo)記為 Common 屬性玉锌。DefaultMode 是 App 平時(shí)所處的狀態(tài),TrackingRunLoopMode 是追蹤 ScrollView 滑動(dòng)時(shí)的狀態(tài)疟羹。當(dāng)你創(chuàng)建一個(gè) Timer 并加到 DefaultMode 時(shí)主守,Timer 會(huì)得到重復(fù)回調(diào)禀倔,但此時(shí)滑動(dòng)一個(gè) TableView 時(shí),RunLoop 會(huì)將 mode 切換為 TrackingRunLoopMode参淫,這時(shí) Timer 就不會(huì)被回調(diào)救湖,并且也不會(huì)影響到滑動(dòng)操作,因?yàn)檫@個(gè) Timer 作為一個(gè) mode item 并沒有被添加到 commonModeItems 里涎才,所以它不會(huì)被同步到其他 Common Mode 里鞋既。

有時(shí)你需要一個(gè) Timer,在兩個(gè) Mode 中都能得到回調(diào)耍铜,一種辦法就是將這個(gè) Timer 分別加入這兩個(gè) Mode邑闺。還有一種方式,就是將 Timer 加入到頂層的 RunLoop 的 commonModeItems 中棕兼。commonModeItems 被 RunLoop 自動(dòng)更新到所有具有 Common 屬性的 Mode 里去检吆。

CFRunLoop 對(duì)外暴露的管理 Mode 接口只有下面 2 個(gè):

    CFRunLoopAddCommonMode(CFRunLoopRef runloop, CFStringRef modeName);
    CFRunLoopRunInMode(CFStringRef modeName, ...);

Mode 暴露的管理 mode item 的接口有下面幾個(gè):

    CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef modeName);
    CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef modeName);
    CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode);
    CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef modeName);
    CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef modeName);
    CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode);

你只能通過 mode name 來操作內(nèi)部的 mode,當(dāng)你傳入一個(gè)新的 mode name 但 RunLoop 內(nèi)部沒有對(duì)應(yīng) mode 時(shí)程储,RunLoop會(huì)自動(dòng)幫你創(chuàng)建對(duì)應(yīng)的 CFRunLoopModeRef蹭沛。對(duì)于一個(gè) RunLoop 來說,其內(nèi)部的 mode 只能增加不能刪除章鲤。

蘋果公開提供的 Mode 有兩個(gè)摊灭,你可以用這兩個(gè) Mode Name 來操作其對(duì)應(yīng)的 Mode:

  • kCFRunLoopDefaultMode (NSDefaultRunLoopMode)
  • UITrackingRunLoopMode

同時(shí)蘋果還提供了一個(gè)操作 Common 標(biāo)記的字符串:kCFRunLoopCommonModes (NSRunLoopCommonModes),你可以用這個(gè)字符串來操作 Common Items败徊,或標(biāo)記一個(gè) Mode 為 Common帚呼。使用時(shí)注意區(qū)分這個(gè)字符串和其他 mode name。


更多:iOS面試題合集

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末皱蹦,一起剝皮案震驚了整個(gè)濱河市煤杀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌沪哺,老刑警劉巖沈自,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異辜妓,居然都是意外死亡枯途,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門籍滴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酪夷,“玉大人,你說我怎么就攤上這事孽惰⊥砹耄” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵勋功,是天一觀的道長(zhǎng)坦报。 經(jīng)常有香客問我库说,道長(zhǎng),這世上最難降的妖魔是什么燎竖? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任璃弄,我火速辦了婚禮,結(jié)果婚禮上构回,老公的妹妹穿的比我還像新娘夏块。我一直安慰自己,他們只是感情好纤掸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布脐供。 她就那樣靜靜地躺著,像睡著了一般借跪。 火紅的嫁衣襯著肌膚如雪政己。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天掏愁,我揣著相機(jī)與錄音歇由,去河邊找鬼。 笑死果港,一個(gè)胖子當(dāng)著我的面吹牛沦泌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辛掠,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谢谦,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了萝衩?” 一聲冷哼從身側(cè)響起回挽,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎猩谊,沒想到半個(gè)月后千劈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡预柒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年队塘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宜鸯。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖遮怜,靈堂內(nèi)的尸體忽然破棺而出淋袖,到底是詐尸還是另有隱情,我是刑警寧澤锯梁,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布即碗,位于F島的核電站焰情,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏剥懒。R本人自食惡果不足惜内舟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望初橘。 院中可真熱鬧验游,春花似錦、人聲如沸保檐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽夜只。三九已至垒在,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扔亥,已是汗流浹背场躯。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旅挤,地道東北人踢关。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像谦铃,于是被迫代替她去往敵國(guó)和親耘成。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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

  • http://www.cocoachina.com/ios/20150601/11970.html RunLoop...
    紫色冰雨閱讀 835評(píng)論 0 3
  • 轉(zhuǎn)自bireme驹闰,原地址:https://blog.ibireme.com/2015/05/18/runloop/...
    乜_啊_閱讀 1,369評(píng)論 0 5
  • 前言 RunLoop是iOS和OSX開發(fā)中非潮窬基礎(chǔ)的一個(gè)概念,這篇文章將從CFRunLoop的源碼入手嘹朗,介紹Run...
    暮年古稀ZC閱讀 2,242評(píng)論 1 19
  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20150601/11970.html RunL...
    Gatling閱讀 1,438評(píng)論 0 13
  • 1. 背景 在搜索數(shù)據(jù)庫中的數(shù)據(jù)時(shí)师妙,我們經(jīng)常會(huì)用到模糊查詢,在模糊查詢中屹培,我們需要了解一些通配符默穴。 2.SQL中的...
    開心果_9066閱讀 2,391評(píng)論 0 2