NSRunloop簡(jiǎn)單細(xì)說(shuō)(一)—— 整體了解

版本記錄

版本號(hào) 時(shí)間
V1.0 2017.08.22

前言

NSRunloopOC Foundation框架中非常重要的一個(gè)類般眉,很多時(shí)候我們會(huì)使用它佳鳖,但是未必對(duì)其有深入的了解呼巴,接下來(lái)幾篇我就會(huì)帶著大家重新學(xué)習(xí)一下NSRunloop這個(gè)類,從簡(jiǎn)單到復(fù)雜邀摆,從基本到深化羔挡,我會(huì)一步步的走完洁奈。希望對(duì)大家有所幫助间唉。具體可以參考蘋(píng)果的開(kāi)發(fā)文檔

NSRunloop基本了解

Runloop即運(yùn)行循環(huán)睬魂。NSRunloop是對(duì)CFRunloop的封裝终吼,為什么你的APP放在那里不去動(dòng)它,在某個(gè)時(shí)間點(diǎn)去操作它氯哮,它還會(huì)給你反饋。就是因?yàn)镽unloop的存在商佛,因?yàn)镽unloop的存在喉钢,保證你的程序不會(huì)死。具體可以參見(jiàn)蘋(píng)果開(kāi)發(fā)文檔良姆。也可以在xcode里面下載肠虽。具體可參照下圖。

開(kāi)發(fā)文檔下載

安裝好了以后大家可以從下面的路徑/Applications/Xcode.app/Contents/Developer/Documentation/DocSets查看玛追,具體如下圖所示税课。

文檔路徑

至于開(kāi)發(fā)文檔的使用后面會(huì)單獨(dú)抽出來(lái)一篇和大家詳細(xì)說(shuō)明。

使用command + shift + 0快捷鍵出來(lái)的文檔痊剖,大家也可以參考韩玩。

NSRunloop的本質(zhì)

NSRunloop是對(duì)CFRunloop的封裝。

構(gòu)成元素

NSRunloop主要作用

NSRunloop主要有以下作用:

  • 使程序一直運(yùn)行并接受用戶輸入
  • 決定程序在何時(shí)處理一些Event
  • 調(diào)用解耦(Message Queue)
  • 節(jié)省CPU時(shí)間(沒(méi)事的時(shí)候閑著陆馁,有事的時(shí)候處理)

依賴NSRunloop的類和框架

  • NSTimer
  • UIEvent
  • autorelease
  • NSObject(NSDelaydPerforming)
  • NSObject(NSThreadPerformAddtion)
  • CADisplayLink
  • CATransition
  • CAAnimation
  • dispatch_get_main_queue()

NSRunloop消息類型

下面我們看一下消息類型找颓,其實(shí)就是很經(jīng)典那個(gè)圖。

NSRunloop消息類型
  • Port
    監(jiān)聽(tīng)程序的Mach ports叮贩,Mach ports是一個(gè)比較底層的東西击狮,可以簡(jiǎn)單的理解為:內(nèi)核通過(guò)port這種方式將信息發(fā)送,而mach則監(jiān)聽(tīng)內(nèi)核發(fā)來(lái)的port信息益老,然后將其整理彪蓬,打包發(fā)給runloop。

  • Customer
    很明顯捺萌,由開(kāi)發(fā)人員自己發(fā)送档冬。不僅僅是發(fā)送,過(guò)程的話相當(dāng)復(fù)雜互婿,蘋(píng)果也提供了一個(gè)CFRunLoopSource來(lái)幫助處理捣郊。由于很少用到,可以簡(jiǎn)單說(shuō)下核心慈参,但是對(duì)幫助我們理解runloop卻很有幫助:

    • 定義輸入源(數(shù)據(jù)結(jié)構(gòu))
    • 將輸入源添加到runloop呛牲,那么這樣就有了接受者,即為R1驮配。
    • 協(xié)調(diào)輸入源的客戶端(單獨(dú)線程)娘扩,專門(mén)監(jiān)聽(tīng)消息着茸,然后將消息打包成runloop能夠處理的樣式,即第一步定義的輸入源琐旁。它類似Mach的功能涮阔。
    • 誰(shuí)來(lái)發(fā)送消息的問(wèn)題?上面的machport是由內(nèi)核發(fā)送的灰殴。自定義的當(dāng)然要我們自己發(fā)送了敬特。。牺陶。首先必須是另一個(gè)線程來(lái)發(fā)送(當(dāng)然如果只是測(cè)試的話可以和第三步在同一個(gè)線程)伟阔,先發(fā)送消息給輸入源,然后喚醒R1掰伸,因?yàn)镽1一般處于休眠狀態(tài)皱炉,然后R1根據(jù)輸入源來(lái)做相應(yīng)的處理。
  • Selector Sources
    NSObject類提供了很多方法供我們使用狮鸭,這些方法是添加到runloop的合搅,所以如果沒(méi)有開(kāi)啟runloop的話,不會(huì)運(yùn)行歧蕉。

  • Timer Sources:它的事件發(fā)送是同步的灾部,這個(gè)用的比較多。

  • Observers廊谓,觀察者:首先它并不屬于事件源(不會(huì)影響runloop的生命周期)梳猪,它比較特殊,用于觀察runloop自身的一些狀態(tài)的蒸痹,有以下幾種:

    • 進(jìn)入runloop
    • runloop即將執(zhí)行定時(shí)器
    • runloop即將執(zhí)行輸入源(Port春弥,Customer,Selector Sources)
    • runloop即將休眠
    • runloop被喚醒叠荠,在處理完喚醒它的事件之前
    • 退出

NSRunloop API文檔

下面我們就看一下蘋(píng)果給我們預(yù)留的API文檔匿沛。

#import <Foundation/NSObject.h>
#import <Foundation/NSDate.h>
#import <CoreFoundation/CFRunLoop.h>

@class NSTimer, NSPort, NSArray<ObjectType>, NSString;

NS_ASSUME_NONNULL_BEGIN

FOUNDATION_EXPORT NSRunLoopMode const NSDefaultRunLoopMode;
FOUNDATION_EXPORT NSRunLoopMode const NSRunLoopCommonModes NS_AVAILABLE(10_5, 2_0);

//這里是NSRunLoop本類
@interface NSRunLoop : NSObject {
@private
    id          _rl;
    id          _dperf;
    id          _perft;
    id          _info;
    id          _ports;
    void        *_reserved[6];
}

#if FOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8)
@property (class, readonly, strong) NSRunLoop *currentRunLoop;
@property (class, readonly, strong) NSRunLoop *mainRunLoop NS_AVAILABLE(10_5, 2_0);
#endif

@property (nullable, readonly, copy) NSRunLoopMode currentMode;

- (CFRunLoopRef)getCFRunLoop CF_RETURNS_NOT_RETAINED;

- (void)addTimer:(NSTimer *)timer forMode:(NSRunLoopMode)mode;

- (void)addPort:(NSPort *)aPort forMode:(NSRunLoopMode)mode;
- (void)removePort:(NSPort *)aPort forMode:(NSRunLoopMode)mode;

- (nullable NSDate *)limitDateForMode:(NSRunLoopMode)mode;
- (void)acceptInputForMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;

@end

//這里是NSRunLoop其中的一個(gè)分類NSRunLoopConveniences
@interface NSRunLoop (NSRunLoopConveniences)

- (void)run; 
- (void)runUntilDate:(NSDate *)limitDate;
- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;

#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
- (void)configureAsServer NS_DEPRECATED(10_0, 10_5, 2_0, 2_0);
#endif

/// Schedules the execution of a block on the target run loop in given modes.
/// - parameter: modes   An array of input modes for which the block may be executed.
/// - parameter: block   The block to execute
- (void)performInModes:(NSArray<NSRunLoopMode> *)modes block:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

/// Schedules the execution of a block on the target run loop.
/// - parameter: block   The block to execute
- (void)performBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

@end

/****************   Delayed perform  ******************/
@interface NSObject (NSDelayedPerforming)

- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes;
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(nullable id)anArgument;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;

@end

//這里是NSRunLoop其中的一個(gè)分類NSOrderedPerform
@interface NSRunLoop (NSOrderedPerform)

- (void)performSelector:(SEL)aSelector target:(id)target argument:(nullable id)arg order:(NSUInteger)order modes:(NSArray<NSRunLoopMode> *)modes;
- (void)cancelPerformSelector:(SEL)aSelector target:(id)target argument:(nullable id)arg;
- (void)cancelPerformSelectorsWithTarget:(id)target;

@end

從這個(gè)API文檔上我們可以看見(jiàn),提供的是一個(gè)本類榛鼎,兩個(gè)分類(NSRunLoopConveniencesNSOrderedPerform)逃呼。下面以表格的形式給出。

模塊 內(nèi)容
獲取Runloop及其模式 @property(class, readonly, strong) NSRunLoop *currentRunLoop;
@property(readonly, copy) NSRunLoopMode currentMode;
- (NSDate *)limitDateForMode:(NSRunLoopMode)mode;
@property(class, readonly, strong) NSRunLoop *mainRunLoop;
- (CFRunLoopRef)getCFRunLoop;
定時(shí)器管理 - (void)addTimer:(NSTimer *)timer forMode:(NSRunLoopMode)mode;
端口Ports管理 - (void)addPort:(NSPort *)aPort forMode:(NSRunLoopMode)mode;
- (void)removePort:(NSPort *)aPort forMode:(NSRunLoopMode)mode;
configureAsServer - (void)configureAsServer;
Running a loop - (void)run;
- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
- (void)runUntilDate:(NSDate *)limitDate;
- (void)acceptInputForMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
scheduling and canceling Messages - (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray<NSRunLoopMode> *)modes;
- (void)cancelPerformSelector:(SEL)aSelector target:(id)target argument:(id)arg;
- (void)cancelPerformSelectorsWithTarget:(id)target;
Run Loop Modes - (void)performBlock:(void (^)(void))block;
- (void)performInModes:(NSArray<NSRunLoopMode> *)modes block:(void (^)(void))block;

下面我們就看一下文檔里面給出的NSRunloop主要的方法和屬性等信息者娱。

NSRunloop主要的方法和屬性

參考文章

1. iOS NSRunloop詳解
2. NSRunLoop原理詳解——不再有盲點(diǎn)

后記

未完抡笼,待續(xù)~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市黄鳍,隨后出現(xiàn)的幾起案子推姻,更是在濱河造成了極大的恐慌,老刑警劉巖框沟,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藏古,死亡現(xiàn)場(chǎng)離奇詭異增炭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)拧晕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)隙姿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人厂捞,你說(shuō)我怎么就攤上這事输玷。” “怎么了蔫敲?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵饲嗽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我奈嘿,道長(zhǎng),這世上最難降的妖魔是什么吞加? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任裙犹,我火速辦了婚禮,結(jié)果婚禮上衔憨,老公的妹妹穿的比我還像新娘叶圃。我一直安慰自己,他們只是感情好践图,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布掺冠。 她就那樣靜靜地躺著,像睡著了一般码党。 火紅的嫁衣襯著肌膚如雪德崭。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天揖盘,我揣著相機(jī)與錄音眉厨,去河邊找鬼。 笑死兽狭,一個(gè)胖子當(dāng)著我的面吹牛憾股,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播箕慧,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼服球,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了颠焦?” 一聲冷哼從身側(cè)響起斩熊,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒸健,沒(méi)想到半個(gè)月后座享,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體婉商,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年渣叛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丈秩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡淳衙,死狀恐怖蘑秽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情箫攀,我是刑警寧澤肠牲,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站靴跛,受9級(jí)特大地震影響缀雳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜梢睛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一肥印、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绝葡,春花似錦深碱、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至愉阎,卻和暖如春绞蹦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诫硕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工坦辟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人章办。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓锉走,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親藕届。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挪蹭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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