什么是Runloop?
RunLoop是一個事件處理循環(huán),是一種讓線程能隨時處理事件但不退出的機(jī)制公壤。它的目的是為了讓線程在有消息到來時能夠被立即喚醒執(zhí)行任務(wù)鞠呈,在沒有消息使能夠使線程休眠避免資源占用。
一般來講帆疟,一個線程一次只能執(zhí)行一個任務(wù),執(zhí)行完成后線程就會退出宇立。Event Loop模型提供了一個機(jī)制踪宠,讓線程能隨時處理事件但并不退出,他的代碼邏輯大概是這樣的:
function loop() {
initialize();
do {
var message = get_next_message();
process_message(message);
} while (message != quit);
}
NSRunLoop是對Event Loop模型的一種具體實(shí)現(xiàn)妈嘹。
運(yùn)行循環(huán)從兩種不同類型的源接收事件柳琢。輸入源提供異步事件,通常是來自另一個線程或來自不同應(yīng)用程序的消息润脸。定時器源提供在指定時間執(zhí)行或指定時間間隔重復(fù)執(zhí)行的同步事件柬脸。兩種類型的源都使用特定于應(yīng)用程序的處理程序例程來處理事件。
Run Loop Modes
一個run loop mode就是input sources(Port-Based Sources毙驯、Custom Input Sources倒堕、Cocoa Perform Selector Sources)、Timers和該run loop所有的監(jiān)聽者(observers)的集合爆价。每次執(zhí)行run loop都需要指定一個mode涩馆。不同mode通過名稱區(qū)分。
Cocoa和Core Foundation都定義了默認(rèn)模式和幾種常用模式允坚,以及用于在代碼中指定這些模式的字符串。您只需為模式名稱指定自定義字符串即可定義自定義模式蛾号。
Foundation框架常用的mode有以下幾種:
NSDefaultRunLoopMode
會經(jīng)常使用,默認(rèn)模式是用于大多數(shù)操作的模式稠项。大多數(shù)情況下,您應(yīng)該使用此模式啟動運(yùn)行循環(huán)并配置輸入源鲜结。NSEventTrackingRunLoopMode
使用此模式在鼠標(biāo)拖動循環(huán)和其他種類的用戶界面跟蹤循環(huán)期間限制傳入事件展运。NSModalPanelRunLoopMode
A run loop should be set to this mode when waiting for input from a modal panel, such as NSSavePanel or NSOpenPanel.UITrackingRunLoopMode
The mode set while tracking in controls takes place. You can use this mode to add timers that fire during tracking.
在控件中觸發(fā)用戶界面跟蹤時使用該模式. 可以用該模式添加需要在用戶界面跟蹤起價執(zhí)行的timer.NSRunLoopCommonModes
會經(jīng)常使用,這是一組可配置的常用模式精刷。將輸入源與此模式相關(guān)聯(lián)也會將其與組中的每個模式相關(guān)聯(lián)拗胜。也就是說,關(guān)聯(lián)到這個模式的事件或輸入源會自動關(guān)聯(lián)到這個組下面其他的模式怒允。
對于Foundation應(yīng)用程序埂软,此集合默認(rèn)包括NSDefaultRunLoopMode,NSModalPanelRunLoopMode和NSEventTrackingRunLoopMode纫事。UITrackingRunLoopMode在Threading Programming Guide中沒有說明勘畔,但是在NSRunLoopMode的Reference中有說明所灸,不確定是否包含。
這也就是為什么炫七,當(dāng)我們需要添加一個可以在UIScrollView滑動時也可以執(zhí)行的timer時爬立,需要將timer添加到NSRunLoopCommonModes的RunLoop。因?yàn)楫?dāng)我們滑動UIScrollView時万哪,RunLoop會切換到NSEventTrackingRunLoopMode執(zhí)行侠驯,將timer添加到NSRunLoopCommonModes模式的RunLoop時,會自動把這個timer添加到這個組下面其他的模式奕巍。
Input Sources
輸入源一般有兩種吟策,一種是基于端口的輸入源,監(jiān)聽?wèi)?yīng)用程序的Mach端口傳遞的事件伍绳,操作系統(tǒng)內(nèi)核會自動發(fā)送信號踊挠。一種是自定義輸入源,監(jiān)聽自定義源的事件冲杀,需要從其他線程手動發(fā)送信號效床。
Port-Based Sources
Cocoa和Core Foundation框架對使用端口對象和函數(shù)創(chuàng)建基于端口的輸入源提供了內(nèi)建支持。你不需要直接去創(chuàng)建輸入源权谁,而是通過創(chuàng)建一個NSPort對象并使用NSPort對象的方法將端口添加到run loop剩檀。NSPort對象會幫你處理輸入源需要的創(chuàng)建和配置工作。
Custom Input Sources
自定義輸入源旺芽,除了要定義事件到達(dá)之后的行為沪猴,還需要自己定義事件傳遞機(jī)制。
Cocoa Perform Selector Sources
除了基于端口的源采章,Cocoa還定義了一個自定義輸入源用于在任何線程執(zhí)行選擇器运嗜。與基于端口的源不同,執(zhí)行選擇器源會在執(zhí)行完他的選擇器之后把自身從run loop中移除悯舟。
當(dāng)你在其他線程執(zhí)行一個選擇器時担租,目標(biāo)線程必須有一個活動的run loop,這對于你自己創(chuàng)建的線程來說抵怎,意味著你必須在代碼里面顯示的開啟了run loop之后才會執(zhí)行選擇器奋救。添加到主線程的選擇器會被立即執(zhí)行,是因?yàn)閼?yīng)用程序啟動時主線程已經(jīng)默認(rèn)創(chuàng)了一個活動的run loop反惕。
Timer Sources
定時器源傳遞同步事件尝艘,用于通知線程在指定的時間去處理響應(yīng)的事情。定時器需要跟指定的mode關(guān)聯(lián)姿染,如果定時器沒有在當(dāng)前正在執(zhí)行的mode中背亥,那么它并不會被觸發(fā)。定時器源并不是實(shí)時的,它可能存在延遲隘梨。
Run Loop Observers
run loop會在執(zhí)行過程中的特定時間想觀察者發(fā)送消息程癌。這些時間點(diǎn)包括:
- The entrance to the run loop.
- When the run loop is about to process a timer.
- When the run loop is about to process an input source.
- When the run loop is about to go to sleep.
- When the run loop has woken up, but before it has processed the event that woke it up.
- The exit from the run loop.
可以使用Core Foundation框架中的CFRunLoopObserverRef對象向run loop注冊觀察者。
RunLoop與線程
1.每條線程都有唯一的與之對應(yīng)的RunLoop對象轴猎。
2.主線程的RunLoop已經(jīng)創(chuàng)建好了嵌莉,而子線程的需要手動創(chuàng)建。(也就是說子線程的RunLoop默認(rèn)是關(guān)閉的捻脖,因?yàn)橛袝r候開了個線程但卻沒有必要開一個RunLoop锐峭。 )
3.RunLoop在第一次獲取時創(chuàng)建,在線程結(jié)束時銷毀可婶。