版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2017.08.23 |
前言
NSRunloop
是OC Foundation
框架中非常重要的一個類,很多時候我們會使用它,但是未必對其有深入的了解,接下來幾篇我就會帶著大家重新學(xué)習(xí)一下NSRunloop
這個類,從簡單到復(fù)雜雄右,從基本到深化,我會一步步的走完纺讲。希望對大家有所幫助擂仍。感興趣的可以看我上一篇。
1. NSRunloop簡單細(xì)說(一)—— 整體了解
2. NSRunloop簡單細(xì)說(二)—— 獲取運(yùn)行循環(huán)及其模式
3. NSRunloop簡單細(xì)說(三)—— 定時器和端口
4. NSRunloop簡單細(xì)說(四)—— 開啟Runloop
5. NSRunloop簡單細(xì)說(五)—— 調(diào)度和取消消息
幾種循環(huán)模式簡介
關(guān)于循環(huán)模式可以參考文檔
運(yùn)行循環(huán)模式是要監(jiān)視的輸入源和定時源的集合熬甚,以及要通知的運(yùn)行循環(huán)觀察器的集合逢渔。 每次運(yùn)行運(yùn)行循環(huán)時,都可以指定(顯式地或隱式地)運(yùn)行一個特定的“模式”乡括。 在運(yùn)行循環(huán)的通過期間肃廓,僅監(jiān)視與該模式相關(guān)聯(lián)的源,并允許其傳遞其事件诲泌。 (同樣盲赊,只有與該模式關(guān)聯(lián)的觀察者才會被通知運(yùn)行循環(huán)的進(jìn)度。 與其他模式相關(guān)聯(lián)的源將持續(xù)到任何新事件敷扫,直到以適當(dāng)模式通過循環(huán)角钩。
在您的代碼中,您可以按名稱識別模式呻澜。Cocoa
和Core Foundation
都定義了默認(rèn)模式和幾種常用模式,以及用于在代碼中指定這些模式的字符串惨险。 您可以通過簡單地為模式名稱指定自定義字符串來定義自定義模式羹幸。 雖然您分配給自定義模式的名稱是任意的,但這些模式的內(nèi)容不是辫愉。 您必須確保將一個或多個輸入源栅受,計(jì)時器或運(yùn)行循環(huán)觀察器添加到您創(chuàng)建的任何模式,使其有用恭朗。
您可以使用模式在特定通過運(yùn)行循環(huán)的過程中過濾來自不需要的源的事件屏镊。 大多數(shù)情況下,您將要在系統(tǒng)定義的“默認(rèn)”模式下運(yùn)行運(yùn)行循環(huán)痰腮。 但是而芥,模態(tài)面板可能會以“模態(tài)”模式運(yùn)行。 在此模式下膀值,只有與模式面板相關(guān)的來源才會將事件傳遞給線程棍丐。 對于輔助線程误辑,可以使用自定義模式來防止低優(yōu)先級源在時間緊迫的操作期間傳遞事件。
這里還要注意:模式根據(jù)事件的來源進(jìn)行區(qū)分歌逢,而不是事件的類型巾钉。 例如,您不會使用模式僅匹配鼠標(biāo)向下事件或僅匹配鍵盤事件秘案。 您可以使用模式來監(jiān)聽不同的端口集砰苍,臨時暫停定時器,或以其他方式更改源和運(yùn)行當(dāng)前正在監(jiān)視的循環(huán)觀察器阱高。
其實(shí)前面我們都已經(jīng)簡要的說了一下NSRunloop的幾種循環(huán)模式了赚导,這一篇主要就是擴(kuò)展,詳細(xì)的說一下這幾種循環(huán)模式讨惩。
FOUNDATION_EXPORT NSRunLoopMode const NSDefaultRunLoopMode;
FOUNDATION_EXPORT NSRunLoopMode const NSRunLoopCommonModes NS_AVAILABLE(10_5, 2_0);
typedef NSString * NSRunLoopMode NS_EXTENSIBLE_STRING_ENUM;
系統(tǒng)為我們提供了多種模式辟癌,如下所示:
-
Default
模式- 定義:NSDefaultRunLoopMode (Cocoa) kCFRunLoopDefaultMode (Core Foundation)描述:默認(rèn)模式中幾乎包含了所有輸入源(NSConnection除外),一般情況下應(yīng)使用此模式。
-
Connection
模式- 定義:
NSConnectionReplyMode(Cocoa)
描述:處理NSConnection對象相關(guān)事件荐捻,系統(tǒng)內(nèi)部使用黍少,用戶基本不會使用。
- 定義:
-
Modal
模式- 定義:
NSModalPanelRunLoopMode(Cocoa)
描述:處理modal panels事件处面。
- 定義:
-
Event tracking
模式- 定義:UITrackingRunLoopMode(iOS)
NSEventTrackingRunLoopMode(cocoa)
描述:在拖動loop或其他user interface tracking loops時處于此種模式下厂置,在此模式下會限制輸入事件的處理。例如魂角,當(dāng)手指按住UITableView拖動時就會處于此模式昵济。
- 定義:UITrackingRunLoopMode(iOS)
-
Common
模式- 定義:NSRunLoopCommonModes (Cocoa) kCFRunLoopCommonModes (Core Foundation)描述:這是一個偽模式,其為一組run loop mode的集合野揪,將輸入源加入此模式意味著在Common Modes中包含的所有模式下都可以處理访忿。在Cocoa應(yīng)用程序中,默認(rèn)情況下Common Modes包含
default modes
,modal modes
,event Tracking modes
斯稳『C可使用CFRunLoopAddCommonMode方法想Common Modes中添加自定義modes。
- 定義:NSRunLoopCommonModes (Cocoa) kCFRunLoopCommonModes (Core Foundation)描述:這是一個偽模式,其為一組run loop mode的集合野揪,將輸入源加入此模式意味著在Common Modes中包含的所有模式下都可以處理访忿。在Cocoa應(yīng)用程序中,默認(rèn)情況下Common Modes包含
下面我們就詳細(xì)的研究一下這幾個運(yùn)行模式挣惰。
一卧斟、NSDefaultRunLoopMode
這個是默認(rèn)的運(yùn)行模式,也是最常用的運(yùn)行模式憎茂,NSTimer
與NSURLConnection
默認(rèn)運(yùn)行該模式下珍语,所以如果我們不改變定時器的運(yùn)行模式,讓他在這個模式下運(yùn)行竖幔,那么當(dāng)我們拖動控件的時候板乙,變?yōu)?code>UITrackingRunLoopMode模式時,NSTimer
就不能響應(yīng)了拳氢,解決方法就是將定時器加入到UITrackingRunLoopMode
和NSRunLoopCommonModes
亡驰。另外晓猛,還有一種方法就是:將 Timer 加入到頂層的 RunLoop
的 commonModeItems
中。commonModeItems
被 RunLoop 自動更新到所有具有Common
屬性的 Mode 里去凡辱。
默認(rèn)模式是用于大多數(shù)操作的模式戒职。 大多數(shù)情況下,您應(yīng)該使用此模式啟動運(yùn)行循環(huán)并配置輸入源透乾。一般用于處理NSConnection
對象以外的輸入源的模式
二洪燥、NSConnectionReplyMode
Cocoa
將此模式與NSConnection
對象結(jié)合使用來監(jiān)視回復(fù)。 你很少需要自己使用這種模式乳乌。
三捧韵、NSModalPanelRunLoopMode
Cocoa使用此模式來識別用于模式面板的事件。
四汉操、UITrackingRunLoopMode
Cocoa使用此模式在鼠標(biāo)拖動循環(huán)和其他類型的用戶界面跟蹤循環(huán)期間限制傳入事件再来。
五、NSRunLoopCommonModes
這是一組可配置的常用模式磷瘤。 將輸入源與此模式相關(guān)聯(lián)還將其與組中的每種模式相關(guān)聯(lián)芒篷。 對于Cocoa應(yīng)用程序,默認(rèn)情況下采缚,此設(shè)置包括default
, modal
, 和event tracking
针炉。 Core Foundation
最初只包含默認(rèn)模式。 您可以使用CFRunLoopAddCommonMode
函數(shù)向該集合添加自定義模式扳抽。
主線程的 RunLoop 里有兩個預(yù)置的 Mode:kCFRunLoopDefaultMode
和 UITrackingRunLoopMode
篡帕。這兩個 Mode 都已經(jīng)被標(biāo)記為”Common”屬性。
這里還要說一下底層的東西贸呢,CFRunLoopMode
镰烧,這個是NSRunLoopMode在C語言的底層,是一個結(jié)構(gòu)體楞陷,如下所示怔鳖。
struct __CFRunLoopMode {
CFStringRef _name; // Mode Name, 例如 @"kCFRunLoopDefaultMode"
CFMutableSetRef _sources0; // Set
CFMutableSetRef _sources1; // Set
CFMutableArrayRef _observers; // Array
CFMutableArrayRef _timers; // Array
...
};
下面也順便看一下NSRunLoop的C語言底層。
struct __CFRunLoop {
CFMutableSetRef _commonModes; // Set
CFMutableSetRef _commonModeItems; // Set<Source/Observer/Timer>
CFRunLoopModeRef _currentMode; // Current Runloop Mode
CFMutableSetRef _modes; // Set
...
};
這里有個概念叫 CommonModes
:一個 Mode 可以將自己標(biāo)記為Common
屬性(通過將其 ModeName 添加到 RunLoop 的 “commonModes” 中)猜谚。每當(dāng) RunLoop 的內(nèi)容發(fā)生變化時,RunLoop 都會自動將 _commonModeItems 里的 Source/Observer/Timer 同步到具有 “Common” 標(biāo)記的所有Mode里赌渣。
CFRunLoop
對外暴露的管理 Mode 接口只有下面2個:
CFRunLoopAddCommonMode(CFRunLoopRef runloop, CFStringRef modeName);
CFRunLoopRunInMode(CFStringRef modeName, ...);
Mode 暴露的管理 mode item 的接口有下面幾個:
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);
你只能通過 modeName
來操作內(nèi)部的 mode魏铅,當(dāng)你傳入一個新的modeName
但 RunLoop 內(nèi)部沒有對應(yīng) mode 時,RunLoop會自動幫你創(chuàng)建對應(yīng)的 CFRunLoopModeRef
坚芜。對于一個 RunLoop 來說览芳,其內(nèi)部的 mode 只能增加不能刪除。
參考文章
1. iOS中NSRunLoop的模式
2. 深入理解RunLoop
后記
未完鸿竖,待續(xù)~~~