RunLoop

http://www.cocoachina.com/ios/20150601/11970.html

一個(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旱易,讓其互不影響。

CFRunLoopSourceRef 是事件產(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 的線程度苔,其原理在下面會(huì)講到浑度。

上面的 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)无午。

你只能通過 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è):kCFRunLoopDefaultMode (NSDefaultRunLoopMode) 和 UITrackingRunLoopMode袭异,你可以用這兩個(gè) Mode Name 來操作其對(duì)應(yīng)的 Mode炬藤。

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

總結(jié)來說,runMode:beforeDate:
表示的是 runloop 的單次調(diào)用延塑,另外兩者則是循環(huán)調(diào)用。


總的來說,如果你還想從 runloop 里面退出來冕广,就不能用 run
方法。根據(jù)實(shí)踐結(jié)果和文檔沟优,另外兩種啟動(dòng)方法也無法手動(dòng)退出。

這里其實(shí)不正確**runMode:beforeDate: 這個(gè)方法開始的 runloop 其實(shí)是可以手動(dòng)停止的
**

CFRunLoopStop() 方法只會(huì)結(jié)束當(dāng)前的 runMode:beforeDate: 調(diào)用宾肺,而不會(huì)結(jié)束后續(xù)的調(diào)用锨用。

當(dāng)調(diào)用 NSObject 的 performSelecter:afterDelay: 后隘谣,實(shí)際上其內(nèi)部會(huì)創(chuàng)建一個(gè) Timer 并添加到當(dāng)前線程的 RunLoop 中。所以如果當(dāng)前線程沒有 RunLoop掌栅,則這個(gè)方法會(huì)失效码泛。

當(dāng)調(diào)用 performSelector:onThread: 時(shí),實(shí)際上其會(huì)創(chuàng)建一個(gè) Timer 加到對(duì)應(yīng)的線程去晌缘,同樣的痢站,如果對(duì)應(yīng)線程沒有 RunLoop 該方法也會(huì)失效。

RunLoop 啟動(dòng)前內(nèi)部必須要有至少一個(gè) Timer/Observer/Source搀捷,所以 AFNetworking 在 [runLoop run] 之前先創(chuàng)建了一個(gè)新的 NSMachPort 添加進(jìn)去了。通常情況下氢烘,調(diào)用者需要持有這個(gè) NSMachPort (mach_port) 并在外部線程通過這個(gè) port 發(fā)送消息到 loop 內(nèi);但此處添加 port 只是為了讓 RunLoop 不至于退出播玖,并沒有用于實(shí)際的發(fā)送消息蜀踏。

GCD不受RunLoop影響,
普通計(jì)時(shí)器默認(rèn)是被添加到 runloop 的NSDefaultRunLoopMode中的,所以當(dāng)用戶進(jìn)行滑動(dòng)操作的時(shí)候 runloop 切換到UITrackingRunLoopMode,定時(shí)器不在被執(zhí)行

static 的生命周期是整個(gè)工程結(jié)束,如果在方法中聲明那么作用域會(huì)變小,但是不影響其生命周期

這里的 emptyPort 用來維持 runloop 的運(yùn)行掰吕,根據(jù)官方文檔的描述,如果 runloop 中沒有任何 modeItem局待,就不會(huì)啟動(dòng)钳榨,而是立刻退出。之所以選擇作為屬性而不是臨時(shí)變量薛耻,是因?yàn)槲野l(fā)現(xiàn)每次調(diào)用 [NSMachPort port] 方法都會(huì)占用內(nèi)存饼齿,原因暫時(shí)不清楚瘟滨。

NSRunLoop主要是用于objective-c程序,而CFRunLoop主要用于C/C++程序倒淫,這是因?yàn)镃/C++程序無法使用objective-c對(duì)象而創(chuàng)建的一個(gè)類败玉。

**** 所有線程都自動(dòng)創(chuàng)建一個(gè)RunLoop, 在線程內(nèi)通過 [NSRunLoop currentRunLoop] 獲得當(dāng)前線程的RunLoop.****






source0:非基于端口的源
只包含一個(gè)回調(diào)(函數(shù)指針),他不能主動(dòng)觸發(fā)事件


source1:
被用于通過內(nèi)核與其他線程相互發(fā)送消息,能夠主動(dòng)喚醒 RunLoop 的線程

觸摸, 鎖屏, 搖晃 等用戶交互事件


[圖片上傳中返干。。矩欠。(1)]

當(dāng)在其他線程上面執(zhí)行selector時(shí),目標(biāo)線程須有一個(gè)活動(dòng)的run loop躺坟。

cancelPreviousPerformRequestsWithTarget:

cancelPreviousPerformRequestsWithTarget:selector:object:

1.通知觀察者run loop已經(jīng)啟動(dòng)
2.通知觀察者任何即將要開始的定時(shí)器
3.通知觀察者任何即將啟動(dòng)的非基于端口的源
4.處理 ( source0 )

5.如果 source1 準(zhǔn)備好并處于等待狀態(tài)咪橙,立即啟動(dòng)虚倒;并進(jìn)入步驟9。
6.通知觀察者線程進(jìn)入休眠
7.將線程置于休眠直到任一下面的事件發(fā)生:某一事件到達(dá)基于端口的源
定時(shí)器啟動(dòng)
Run loop設(shè)置的時(shí)間已經(jīng)超時(shí)
run loop被顯式喚醒

8.通知觀察者線程將被喚醒菠剩。
9.處理未處理的事件如果用戶定義的定時(shí)器啟動(dòng)赠叼,處理定時(shí)器事件并重啟run loop。進(jìn)入步驟2
如果輸入源啟動(dòng),傳遞相應(yīng)的消息
如果run loop被顯式喚醒而且時(shí)間還沒超時(shí)买鸽,重啟run loop贯被。進(jìn)入步驟2

10.通知觀察者run loop結(jié)束。

Q1: 添加到滑動(dòng) Model 中的計(jì)時(shí)器 普通狀態(tài)下也走

Q2:

2017.2.23號(hào)重新學(xué)習(xí)記錄

  • 線程和 RunLoop 之間是一一對(duì)應(yīng)的看幼,其關(guān)系是保存在一個(gè)全局的 Dictionary 里幌陕。線程剛創(chuàng)建時(shí)并沒有 RunLoop搏熄,如果你不主動(dòng)獲取,那它一直都不會(huì)有宵凌。RunLoop 的創(chuàng)建是發(fā)生在第一次獲取時(shí)止后,RunLoop 的銷毀是發(fā)生在線程結(jié)束時(shí)。你只能在一個(gè)線程的內(nèi)部獲取其 RunLoop(主線程除外)挺益。

  • 一個(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鸠澈,讓其互不影響笑陈。

  • 這里的 emptyPort 用來維持 runloop 的運(yùn)行,根據(jù)官方文檔的描述乖菱,如果 runloop 中沒有任何 modeItem块请,就不會(huì)啟動(dòng)拳缠,而是立刻退出

  • 這里有個(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里窟坐。

//將 mode 標(biāo)記為為 "Common"屬性
CFRunLoopAddCommonMode(CFRunLoopRef runloop, CFStringRef modeName);
  • "commonModeItems" 被 RunLoop 自動(dòng)更新到所有具有"Common"屬性的 Mode 里去海渊。但是兩個(gè)被標(biāo)記為"Common"的 mode 里面的 item 不會(huì)互相同步

  • 如何切換 runloop 的運(yùn)行 mode
    1.先停止 RunLoop

CFRunLoopStop([runloop getCFRunLoop]);

2.再繼續(xù),此時(shí)切換線程

    [runloop runMode:@"customMode" beforeDate:[NSDate distantFuture]];

線程通訊 NSMachPort

  • Thread ----> RunLoop ----> MachPort
  • 想要給某個(gè)線程發(fā)送消息,需要使用該線程的 MachPort
[ remotePort sendBeforeDate:[NSDate date] msgid:kMsg1 components:array from:myPort reserved:0];
    [remotePort sendBeforeDate:<#(nonnull NSDate *)#> components:<#(nullable NSMutableArray *)#> from:<#(nullable NSPort *)#> reserved:<#(NSUInteger)#>]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绵疲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子臣疑,更是在濱河造成了極大的恐慌盔憨,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讯沈,死亡現(xiàn)場離奇詭異郁岩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)缺狠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門如叼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笼恰,“玉大人,你說我怎么就攤上這事猴仑。” “怎么了篡诽?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵吊圾,是天一觀的道長啰劲。 經(jīng)常有香客問我蝇裤,道長恋拍,這世上最難降的妖魔是什么施敢? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任悯许,我火速辦了婚禮先壕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谆棺。我一直安慰自己改淑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饥侵,像睡著了一般躏升。 火紅的嫁衣襯著肌膚如雪盗温。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音染坯,去河邊找鬼。 笑死仲锄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怀愧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼陶贼!你這毒婦竟也來了痹屹?” 一聲冷哼從身側(cè)響起志衍,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后价匠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鳞骤。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡美旧,死狀恐怖榴嗅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情唠粥,我是刑警寧澤大莫,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布懈凹,位于F島的核電站介评,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望羡蛾。 院中可真熱鬧器予,春花似錦珠移、人聲如沸勾习。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至划煮,卻和暖如春铐懊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國打工碴倾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跌榔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓面褐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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