NSTimer - 計時器
NSTimer派生自NSObject,是一種計時器,在經(jīng)過一定的時間間隔后觸發(fā),向目標對象發(fā)送指定的消息。
計時器(NSTimer)與運行循環(huán)(RunLoop)一起工作。運行循環(huán)維護對其計時器的強引用,因此在將計時器添加到運行循環(huán)后,不必自己維護對計時器的強引用。
計時器不是實時機制。如果計時器的觸發(fā)時間發(fā)生在長運行循環(huán)調(diào)用期間,或者當運行循環(huán)處于不監(jiān)視計時器的模式時,計時器在下次運行循環(huán)檢查計時器之前不會觸發(fā),因此計時器觸發(fā)的實際時間可能要晚得多。
NSTimer創(chuàng)建計時器函數(shù)
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
函數(shù)描述 :使用指定的調(diào)用對象初始化計時器對象。必須使用addTimer:forMode:方法將初始化的計時器添加到運行循環(huán)中(如果計時器配置為重復(fù),則一次計時結(jié)束無需將計時器重新添加到運行循環(huán)中)。然后,在ti過去之后,計時器將觸發(fā),由調(diào)用對象執(zhí)行其調(diào)用。
參數(shù) :
ti :計時器觸發(fā)之間的秒數(shù)。如果ti小于或等于0.0,此方法將選擇非負值0.1毫秒。
invocation :計時器觸發(fā)時要使用的調(diào)用對象。計時器指示調(diào)用對象維護對其參數(shù)的強引用。
repeats :是否重復(fù),如果是YES,計時器將重復(fù)重新安排自己,直到失效。如果NO,計時器將在其觸發(fā)后失效。
返回值 :一個新的根據(jù)指定的參數(shù)進行配置的NSTimer對象。
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
函數(shù)描述 :使用指定的對象和選擇器初始化計時器對象。必須使用addTimer:forMode:方法將新計時器添加到運行循環(huán)中(如果計時器配置為重復(fù),則一次計時結(jié)束無需將計時器重新添加到運行循環(huán)中)。然后,經(jīng)過ti秒后,計時器啟動,向目標發(fā)送selector消息。
參數(shù) :
ti :計時器觸發(fā)之間的秒數(shù)。如果ti小于或等于0.0,此方法將選擇非負值0.1毫秒。
aTarget :當計時器觸發(fā)時,選擇器指定要向其發(fā)送消息的對象。計時器維持對目標的強引用,直到它(計時器)失效。
aSelector :計時器觸發(fā)時要發(fā)送給目標的消息。
repeats :是否重復(fù),如果是YES,計時器將重復(fù)重新安排自己,直到失效。如果NO,計時器將在其觸發(fā)后失效。
返回值 :一個新的根據(jù)指定的參數(shù)進行配置的NSTimer對象。
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (NS_SWIFT_SENDABLE ^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
函數(shù)描述 :使用指定的時間間隔和塊初始化計時器對象。必須使用addTimer:forMode:將新計時器添加到運行循環(huán)中(如果計時器配置為重復(fù),則一次計時結(jié)束無需將計時器重新添加到運行循環(huán)中)。然后,在間隔秒后,計時器啟動,執(zhí)行塊。
參數(shù) :
interval :計時器啟動之間的秒數(shù)。如果間隔小于或等于0.0,此方法將選擇非負值0.1毫秒。
repeats :是否重復(fù),如果是YES,計時器將重復(fù)重新安排自己,直到失效。如果NO,計時器將在其觸發(fā)后失效。
block :計時器啟動時要執(zhí)行的塊。該塊采用單個NSTimer參數(shù),并且沒有返回值。
返回值 :一個新的根據(jù)指定的參數(shù)進行配置的NSTimer對象。
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (NS_SWIFT_SENDABLE ^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
函數(shù)描述 :使用指定日期與時間間隔以及一個塊初始化計時器對象。 必須使用addTimer:forMode:方法將新計時器添加到運行循環(huán)中(如果計時器配置為重復(fù),則一次計時結(jié)束無需將計時器重新添加到運行循環(huán)中)。在指定日期到達后計時器觸發(fā),之后每間隔interval秒,計時器觸發(fā),執(zhí)行block。
參數(shù) :
date :計時器應(yīng)首次啟動的時間。
interval :計時器啟動之間的秒數(shù)。如果間隔小于或等于0.0,此方法將選擇非負值0.1毫秒。
repeats :是否重復(fù),如果是YES,計時器將重復(fù)重新安排自己,直到失效。如果NO,計時器將在其觸發(fā)后失效。
block :計時器啟動時要執(zhí)行的塊。該塊采用單個NSTimer參數(shù),并且沒有返回值。
返回值 :一個新的根據(jù)指定的參數(shù)進行配置的NSTimer對象。
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;
函數(shù)描述 :使用指定的對象和選擇器初始化計時器。必須使用addTimer:forMode:方法將新計時器添加到運行循環(huán)中(如果計時器配置為重復(fù),則一次計時結(jié)束無需將計時器重新添加到運行循環(huán)中)。在指定日期到達后計時器觸發(fā),之后每間隔interval秒,計時器觸發(fā),向目標發(fā)送aSelector消息。
參數(shù) :
date :計時器應(yīng)首次啟動的時間。
ti :計時器啟動之間的秒數(shù)。如果間隔小于或等于0.0,此方法將選擇非負值0.1毫秒。
t :當計時器觸發(fā)時,選擇器指定要向其發(fā)送消息的對象。計時器維持對目標的強引用,直到它(計時器)失效。
s :計時器觸發(fā)時要發(fā)送給目標的消息。
ui : 計時器的用戶信息。計時器維持對這個對象的強引用,直到它(計時器)失效。這個參數(shù)可以是nil。
rep : 是否重復(fù),如果是YES,計時器將重復(fù)重新安排自己,直到失效。如果NO,計時器將在其觸發(fā)后失效。
- (void)viewDidLoad {
[super viewDidLoad];
//獲取方法簽名對象
NSMethodSignature *signature = [self methodSignatureForSelector:NSSelectorFromString(@"timerAction")];
//獲取調(diào)用對象,設(shè)置調(diào)用對象調(diào)用者與調(diào)用消息
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = NSSelectorFromString(@"timerAction");
//計時器加入運行循環(huán)
[[NSRunLoop mainRunLoop] addTimer:[NSTimer timerWithTimeInterval:1.0 invocation:invocation repeats:YES] forMode:NSRunLoopCommonModes];
}
///計時器調(diào)用函數(shù)
- (void)timerAction {
NSLog(@"計時器工作中");
}
不加入運行循環(huán),則只會打印一次,加入運行循環(huán)后,打印如下 :
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
函數(shù)描述 :創(chuàng)建計時器并以默認模式在當前運行循環(huán)上調(diào)度它。在ti秒過去后,計時器觸發(fā),由調(diào)用對象執(zhí)行其調(diào)用。
參數(shù) :
ti :計時器啟動之間的秒數(shù)。如果ti小于或等于0.0,此方法將選擇非負值0.1毫秒。
invocation :計時器觸發(fā)時要使用的調(diào)用對象。計時器指示調(diào)用對象維護對其參數(shù)的強引用。
repeats :是否重復(fù),如果是YES,計時器將重復(fù)重新安排自己,直到失效。如果NO,計時器將在其觸發(fā)后失效。
返回值 : 根據(jù)指定參數(shù)配置的新NSTimer對象。
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
函數(shù)描述 :創(chuàng)建計時器并以默認模式在當前運行循環(huán)上調(diào)度它。在ti秒過去后,計時器觸發(fā),發(fā)送消息選擇器到目標。
參數(shù) :
ti :計時器啟動之間的秒數(shù)。如果ti小于或等于0.0,此方法將選擇非負值0.1毫秒。
aTarget :當計時器觸發(fā)時,選擇器指定要向其發(fā)送消息的對象。計時器維持對目標的強引用,直到它(計時器)失效。
aSelector :計時器觸發(fā)時要發(fā)送給目標的消息。
userInfo : 計時器的用戶信息。計時器維持對這個對象的強引用,直到它(計時器)失效。這個參數(shù)可以是nil。
repeats : 是否重復(fù),如果是YES,計時器將重復(fù)重新安排自己,直到失效。如果NO,計時器將在其觸發(fā)后失效。
返回值 : 根據(jù)指定參數(shù)配置的新NSTimer對象。
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (NS_SWIFT_SENDABLE ^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
函數(shù)描述 :創(chuàng)建一個計時器,并在默認模式下在當前運行循環(huán)中對其進行調(diào)度。在間隔秒后,計時器啟動,執(zhí)行塊。
參數(shù) :
interval : 計時器啟動之間的秒數(shù)。如果間隔小于或等于0.0,此方法將選擇非負值0.1毫秒。
repeats :是否重復(fù),如果是YES,計時器將重復(fù)重新安排自己,直到失效。如果NO,計時器將在其觸發(fā)后失效。
block :計時器啟動時要執(zhí)行的塊。該塊采用單個NSTimer參數(shù),并且沒有返回值。
返回值 :一個新的根據(jù)指定的參數(shù)進行配置的NSTimer對象。
- (void)viewDidLoad {
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
}
///計時器調(diào)用函數(shù)
- (void)timerAction {
NSLog(@"計時器工作中");
}
打印如下 :
NSTimer觸發(fā)與銷毀計時器函數(shù)
- (void)fire;
函數(shù)描述:使計時器的消息被發(fā)送到它的目標。可以使用此方法來觸發(fā)重復(fù)計時器而不中斷其常規(guī)觸發(fā)計劃。如果計時器是非重復(fù)的,它在觸發(fā)后會自動失效,即使它的預(yù)定觸發(fā)日期還沒有到達。
- (void)invalidate;
函數(shù)描述:停止觸發(fā)的計時器,并請求將其從運行循環(huán)中刪除。這個方法是從NSRunLoop對象中刪除計時器的唯一方法。NSRunLoop對象會在invalidate方法返回之前或之后的某個時間點刪除它對計時器的強引用。如果配置了target和userInfo對象,計時器也會刪除對這些對象的強引用。
常用屬性
@property (copy) NSDate *fireDate;
屬性描述:計時器觸發(fā)的日期。如果計時器已經(jīng)失效,則為計時器觸發(fā)的最后日期。可以設(shè)置此屬性以調(diào)整重復(fù)計時器(repeats為YES)的觸發(fā)時間。盡管重置計時器的下一次觸發(fā)時間是一個相對昂貴的操作,但在某些情況下它可能更有效。例如,可以在未來想要以不規(guī)則的時間間隔多次重復(fù)某個操作的情況下使用它。調(diào)整單個計時器的觸發(fā)時間比創(chuàng)建多個計時器對象,在一個運行循環(huán)中調(diào)度每個對象,然后銷毀它們所產(chǎn)生的開銷要小。
對于已經(jīng)失效的計時器(包括已經(jīng)觸發(fā)的非重復(fù)計時器),不應(yīng)該更改其觸發(fā)日期。可以更改尚未觸發(fā)的非重復(fù)計時器的觸發(fā)日期,但應(yīng)該始終從計時器所連接的線程進行更改。使用valid屬性可以驗證計時器是否有效。
@property (readonly) NSTimeInterval timeInterval;
屬性描述:計時器的時間間隔,以秒為單位。如果計時器不重復(fù),即使設(shè)置了時間間隔,也會返回0。
@property NSTimeInterval tolerance API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));
屬性描述:計時器到達預(yù)定觸發(fā)日期,觸發(fā)時可以應(yīng)用的額外時間容差。默認值為0,這意味著沒有應(yīng)用額外的容差。為計時器設(shè)置容差可以使其在預(yù)定觸發(fā)日期到達后,偏移計時器觸發(fā)。計時器可以在預(yù)定觸發(fā)日期與額外時間容差加上預(yù)定觸發(fā)日期之間的任何時間觸發(fā)。允許系統(tǒng)在計時器觸發(fā)時具有靈活性,可以提高系統(tǒng)優(yōu)化的能力,以提高功耗節(jié)省和響應(yīng)能力。
@property (readonly, getter=isValid) BOOL valid;
屬性描述:一個布爾值,用于指示計時器當前是否有效。如果計時器仍然能夠觸發(fā),則為YES;如果計時器已經(jīng)失效并且不再能夠觸發(fā),那么為NO。
@property (nullable, readonly, retain) id userInfo;
屬性描述:計時器的userInfo對象。計時器無效后,不要訪問此屬性。使用valid屬性驗證計時器是否有效。
NSRunLoop - 運行循環(huán)
一個管理輸入源(手勢、Selector等)的對象,Runloop即運行循環(huán),是iOS中的消息處理機制,其主要作用是控制NSRunLoop里面線程的執(zhí)行和休眠,當某個事件執(zhí)行完成后,不退出其線程而進入休眠狀態(tài),當再次檢測到事件時。喚醒休眠的線程繼續(xù)處理事件。RunLoop可以保持程序的持續(xù)運行,并節(jié)省CPU資源,提高程序性能。
NSRunLoop是對CFRunLoopRef的一層封裝, 是Objective-C的語法的框架。CFRunLoopRef是基于C語言的開源框架。
從NSRunLoop的角度來看,NSTimer對象并不是輸入源,它們是一種特殊的類型,當它們被觸發(fā)時,不會導(dǎo)致運行循環(huán)返回。
NSRunLoop類通常不是線程安全的,只能在當前線程的上下文中調(diào)用它的方法。
NSRunLoop 處理事件流程:
NSRunLoop常用屬性
@property (class, readonly, strong) NSRunLoop *currentRunLoop
屬性描述:類屬性,返回當前線程的運行循環(huán)(NSRunLoop對象)。如果線程還不存在運行循環(huán),則會創(chuàng)建并返回一個運行循環(huán)。
@property (class, readonly, strong) NSRunLoop *mainRunLoop API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
屬性描述:類屬性,返回主線程的運行循環(huán)(NSRunLoop對象)。
@property (nullable, readonly, copy) NSRunLoopMode currentMode;
屬性描述:調(diào)用方的當前輸入模式。這個方法僅在調(diào)用方運行時返回當前的輸入模式,否則它返回nil。
- Runloop模式:
1.NSDefaultRunLoopMode:默認狀態(tài)(空閑狀態(tài)),比如點擊按鈕都是這個狀態(tài)
2.UITrackingRunLoopMode:滑動時的Mode。比如滑動UIScrollView時。
3.UIInitializationRunLoopMode:私有的,APP啟動時。就是從iphone桌面點擊APP的圖標進入APP到第一個界面展示之前,在第一個界面顯示出來后,UIInitializationRunLoopMode就被切換成了NSDefaultRunLoopMode。
4.NSRunLoopCommonModes:它是NSDefaultRunLoopMode和UITrackingRunLoopMode的集合。結(jié)構(gòu)類似于一個數(shù)組。在這個mode下執(zhí)行其實就是兩個mode都能執(zhí)行而已。
NSRunLoop常用函數(shù)
- (CFRunLoopRef)getCFRunLoop CF_RETURNS_NOT_RETAINED;
函數(shù)描述:返回調(diào)用方的基礎(chǔ)CFRunLoop對象。可以使用返回的運行循環(huán)來使用Core Foundation函數(shù)調(diào)用配置當前運行循環(huán)。例如可以使用此函數(shù)來設(shè)置運行循環(huán)觀察者。
返回值 :調(diào)用方的基礎(chǔ)CFRunLoop對象。
- (void)addTimer:(NSTimer *)timer forMode:(NSRunLoopMode)mode;
函數(shù)描述:使用給定的輸入模式注冊給定的計時器。可以將計時器添加到多種輸入模式中。在指定模式下運行時,調(diào)用方會使計時器在其計劃的啟動日期當天或之后啟動。觸發(fā)后,計時器調(diào)用其關(guān)聯(lián)的處理程序例程,該例程是指定對象上的選擇器。調(diào)用方保留計時器。要從安裝計時器的所有運行循環(huán)模式中刪除計時器,需要向計時器發(fā)送invalidate消息。
參數(shù) :
timer :要向調(diào)用方注冊的計時器。
mode :添加計時器的模式。