版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2017.08.22 |
前言
NSRunloop
是OC 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里面下載肠虽。具體可參照下圖。
安裝好了以后大家可以從下面的路徑/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
的封裝。
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è)圖。
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è)分類(NSRunLoopConveniences
和 NSOrderedPerform
)逃呼。下面以表格的形式給出。
模塊 | 內(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主要的方法和屬性等信息者娱。
參考文章
1. iOS NSRunloop詳解
2. NSRunLoop原理詳解——不再有盲點(diǎn)
后記
未完抡笼,待續(xù)~~~