Objective-C的NSTimer學習筆記

NSTimer - 計時器

NSTimer派生自NSObject,是一種計時器,在經過一定的時間間隔后觸發,向目標對象發送指定的消息。

計時器(NSTimer)與運行循環(RunLoop)一起工作。運行循環維護對其計時器的強引用,因此在將計時器添加到運行循環后,不必自己維護對計時器的強引用

計時器不是實時機制。如果計時器的觸發時間發生在長運行循環調用期間,或者當運行循環處于不監視計時器的模式時,計時器在下次運行循環檢查計時器之前不會觸發,因此計時器觸發的實際時間可能要晚得多。

NSTimer創建計時器函數
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;

函數描述使用指定的調用對象初始化計時器對象。必須使用addTimer:forMode:方法將初始化的計時器添加到運行循環中(如果計時器配置為重復,則一次計時結束無需將計時器重新添加到運行循環中)。然后,在ti過去之后,計時器將觸發,由調用對象執行其調用。

參數 :

ti :計時器觸發之間的秒數。如果ti小于或等于0.0,此方法將選擇非負值0.1毫秒。

invocation :計時器觸發時要使用的調用對象。計時器指示調用對象維護對其參數的強引用。

repeats :是否重復,如果是YES,計時器將重復重新安排自己,直到失效。如果NO,計時器將在其觸發后失效。

返回值 :一個新的根據指定的參數進行配置的NSTimer對象。

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

函數描述使用指定的對象和選擇器初始化計時器對象。必須使用addTimer:forMode:方法將新計時器添加到運行循環中(如果計時器配置為重復,則一次計時結束無需將計時器重新添加到運行循環中)。然后,經過ti秒后,計時器啟動,向目標發送selector消息。

參數 :

ti :計時器觸發之間的秒數。如果ti小于或等于0.0,此方法將選擇非負值0.1毫秒。

aTarget :當計時器觸發時,選擇器指定要向其發送消息的對象。計時器維持對目標的強引用,直到它(計時器)失效。

aSelector :計時器觸發時要發送給目標的消息。

repeats :是否重復,如果是YES,計時器將重復重新安排自己,直到失效。如果NO,計時器將在其觸發后失效。

返回值 :一個新的根據指定的參數進行配置的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));

函數描述使用指定的時間間隔和塊初始化計時器對象。必須使用addTimer:forMode:將新計時器添加到運行循環中(如果計時器配置為重復,則一次計時結束無需將計時器重新添加到運行循環中)。然后,在間隔秒后,計時器啟動,執行塊。

參數 :

interval :計時器啟動之間的秒數。如果間隔小于或等于0.0,此方法將選擇非負值0.1毫秒。

repeats :是否重復,如果是YES,計時器將重復重新安排自己,直到失效。如果NO,計時器將在其觸發后失效。

block :計時器啟動時要執行的塊。該塊采用單個NSTimer參數,并且沒有返回值。

返回值 :一個新的根據指定的參數進行配置的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));

函數描述使用指定日期與時間間隔以及一個塊初始化計時器對象。 必須使用addTimer:forMode:方法將新計時器添加到運行循環中(如果計時器配置為重復,則一次計時結束無需將計時器重新添加到運行循環中)。在指定日期到達后計時器觸發,之后每間隔interval秒,計時器觸發,執行block。

參數 :

date :計時器應首次啟動的時間。

interval :計時器啟動之間的秒數。如果間隔小于或等于0.0,此方法將選擇非負值0.1毫秒。

repeats :是否重復,如果是YES,計時器將重復重新安排自己,直到失效。如果NO,計時器將在其觸發后失效。

block :計時器啟動時要執行的塊。該塊采用單個NSTimer參數,并且沒有返回值。

返回值 :一個新的根據指定的參數進行配置的NSTimer對象。

- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;

函數描述使用指定的對象和選擇器初始化計時器。必須使用addTimer:forMode:方法將新計時器添加到運行循環中(如果計時器配置為重復,則一次計時結束無需將計時器重新添加到運行循環中)。在指定日期到達后計時器觸發,之后每間隔interval秒,計時器觸發,向目標發送aSelector消息。

參數 :

date :計時器應首次啟動的時間。

ti :計時器啟動之間的秒數。如果間隔小于或等于0.0,此方法將選擇非負值0.1毫秒。

t :當計時器觸發時,選擇器指定要向其發送消息的對象。計時器維持對目標的強引用,直到它(計時器)失效。

s :計時器觸發時要發送給目標的消息。

ui : 計時器的用戶信息。計時器維持對這個對象的強引用,直到它(計時器)失效。這個參數可以是nil。

rep : 是否重復,如果是YES,計時器將重復重新安排自己,直到失效。如果NO,計時器將在其觸發后失效。

\color{red}{例如:需要添加到運行循環中的計時器}

- (void)viewDidLoad {
    [super viewDidLoad];
    //獲取方法簽名對象
    NSMethodSignature *signature = [self methodSignatureForSelector:NSSelectorFromString(@"timerAction")];
    //獲取調用對象,設置調用對象調用者與調用消息
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = NSSelectorFromString(@"timerAction");
    //計時器加入運行循環
    [[NSRunLoop mainRunLoop] addTimer:[NSTimer timerWithTimeInterval:1.0 invocation:invocation repeats:YES] forMode:NSRunLoopCommonModes];
}

///計時器調用函數
- (void)timerAction {
    NSLog(@"計時器工作中");
}

不加入運行循環,則只會打印一次,加入運行循環后,打印如下 :

截屏2023-03-27 11.24.53.png
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;

函數描述創建計時器并以默認模式在當前運行循環上調度它。在ti秒過去后,計時器觸發,由調用對象執行其調用。

參數 :

ti :計時器啟動之間的秒數。如果ti小于或等于0.0,此方法將選擇非負值0.1毫秒。

invocation :計時器觸發時要使用的調用對象。計時器指示調用對象維護對其參數的強引用。

repeats :是否重復,如果是YES,計時器將重復重新安排自己,直到失效。如果NO,計時器將在其觸發后失效。

返回值 : 根據指定參數配置的新NSTimer對象。

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

函數描述創建計時器并以默認模式在當前運行循環上調度它。在ti秒過去后,計時器觸發,發送消息選擇器到目標。

參數 :

ti :計時器啟動之間的秒數。如果ti小于或等于0.0,此方法將選擇非負值0.1毫秒。

aTarget :當計時器觸發時,選擇器指定要向其發送消息的對象。計時器維持對目標的強引用,直到它(計時器)失效。

aSelector :計時器觸發時要發送給目標的消息。

userInfo : 計時器的用戶信息。計時器維持對這個對象的強引用,直到它(計時器)失效。這個參數可以是nil。

repeats : 是否重復,如果是YES,計時器將重復重新安排自己,直到失效。如果NO,計時器將在其觸發后失效。

返回值 : 根據指定參數配置的新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));

函數描述創建一個計時器,并在默認模式下在當前運行循環中對其進行調度。在間隔秒后,計時器啟動,執行塊。

參數 :

interval : 計時器啟動之間的秒數。如果間隔小于或等于0.0,此方法將選擇非負值0.1毫秒。

repeats :是否重復,如果是YES,計時器將重復重新安排自己,直到失效。如果NO,計時器將在其觸發后失效。

block :計時器啟動時要執行的塊。該塊采用單個NSTimer參數,并且沒有返回值。

返回值 :一個新的根據指定的參數進行配置的NSTimer對象。

\color{red}{例如:以默認模式在當前運行循環上執行計時器 }

- (void)viewDidLoad {
    [super viewDidLoad];
    [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
}

///計時器調用函數
- (void)timerAction {
    NSLog(@"計時器工作中");
}

打印如下 :

截屏2023-03-27 15.10.33.png
NSTimer觸發與銷毀計時器函數
- (void)fire;

函數描述:使計時器的消息被發送到它的目標。可以使用此方法來觸發重復計時器而不中斷其常規觸發計劃。如果計時器是非重復的,它在觸發后會自動失效,即使它的預定觸發日期還沒有到達。

- (void)invalidate;

函數描述停止觸發的計時器,并請求將其從運行循環中刪除。這個方法是從NSRunLoop對象中刪除計時器的唯一方法。NSRunLoop對象會在invalidate方法返回之前或之后的某個時間點刪除它對計時器的強引用。如果配置了target和userInfo對象,計時器也會刪除對這些對象的強引用。

常用屬性
@property (copy) NSDate *fireDate;

屬性描述計時器觸發的日期。如果計時器已經失效,則為計時器觸發的最后日期。可以設置此屬性以調整重復計時器(repeats為YES)的觸發時間。盡管重置計時器的下一次觸發時間是一個相對昂貴的操作,但在某些情況下它可能更有效。例如,可以在未來想要以不規則的時間間隔多次重復某個操作的情況下使用它。調整單個計時器的觸發時間比創建多個計時器對象,在一個運行循環中調度每個對象,然后銷毀它們所產生的開銷要小。

對于已經失效的計時器(包括已經觸發的非重復計時器),不應該更改其觸發日期。可以更改尚未觸發的非重復計時器的觸發日期,但應該始終從計時器所連接的線程進行更改。使用valid屬性可以驗證計時器是否有效。

@property (readonly) NSTimeInterval timeInterval;

屬性描述計時器的時間間隔,以秒為單位。如果計時器不重復,即使設置了時間間隔,也會返回0。

@property NSTimeInterval tolerance API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));

屬性描述計時器到達預定觸發日期,觸發時可以應用的額外時間容差。默認值為0,這意味著沒有應用額外的容差。為計時器設置容差可以使其在預定觸發日期到達后,偏移計時器觸發。計時器可以在預定觸發日期與額外時間容差加上預定觸發日期之間的任何時間觸發。允許系統在計時器觸發時具有靈活性,可以提高系統優化的能力,以提高功耗節省和響應能力。

@property (readonly, getter=isValid) BOOL valid;

屬性描述:一個布爾值,用于指示計時器當前是否有效。如果計時器仍然能夠觸發,則為YES;如果計時器已經失效并且不再能夠觸發,那么為NO。

@property (nullable, readonly, retain) id userInfo;

屬性描述計時器的userInfo對象。計時器無效后,不要訪問此屬性。使用valid屬性驗證計時器是否有效。

NSRunLoop - 運行循環

一個管理輸入源(手勢、Selector等)的對象,Runloop即運行循環,是iOS中的消息處理機制,其主要作用是控制NSRunLoop里面線程的執行和休眠,當某個事件執行完成后,不退出其線程而進入休眠狀態,當再次檢測到事件時。喚醒休眠的線程繼續處理事件。RunLoop可以保持程序的持續運行,并節省CPU資源,提高程序性能。

NSRunLoop是對CFRunLoopRef的一層封裝, 是Objective-C的語法的框架。CFRunLoopRef是基于C語言的開源框架。

從NSRunLoop的角度來看,NSTimer對象并不是輸入源,它們是一種特殊的類型,當它們被觸發時,不會導致運行循環返回。

NSRunLoop類通常不是線程安全的,只能在當前線程的上下文中調用它的方法。

NSRunLoop 處理事件流程:

26031781-ad7d1505ba7b3e59.png
NSRunLoop常用屬性
@property (class, readonly, strong) NSRunLoop *currentRunLoop

屬性描述類屬性,返回當前線程的運行循環(NSRunLoop對象)。如果線程還不存在運行循環,則會創建并返回一個運行循環。

@property (class, readonly, strong) NSRunLoop *mainRunLoop API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

屬性描述類屬性,返回主線程的運行循環(NSRunLoop對象)

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

屬性描述:調用方的當前輸入模式。這個方法僅在調用方運行時返回當前的輸入模式,否則它返回nil。

  • Runloop模式:
1.NSDefaultRunLoopMode:默認狀態(空閑狀態),比如點擊按鈕都是這個狀態
2.UITrackingRunLoopMode:滑動時的Mode。比如滑動UIScrollView時。
3.UIInitializationRunLoopMode:私有的,APP啟動時。就是從iphone桌面點擊APP的圖標進入APP到第一個界面展示之前,在第一個界面顯示出來后,UIInitializationRunLoopMode就被切換成了NSDefaultRunLoopMode。
4.NSRunLoopCommonModes:它是NSDefaultRunLoopMode和UITrackingRunLoopMode的集合。結構類似于一個數組。在這個mode下執行其實就是兩個mode都能執行而已。
NSRunLoop常用函數
- (CFRunLoopRef)getCFRunLoop CF_RETURNS_NOT_RETAINED;

函數描述返回調用方的基礎CFRunLoop對象。可以使用返回的運行循環來使用Core Foundation函數調用配置當前運行循環。例如可以使用此函數來設置運行循環觀察者。

返回值 :調用方的基礎CFRunLoop對象。

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

函數描述使用給定的輸入模式注冊給定的計時器。可以將計時器添加到多種輸入模式中。在指定模式下運行時,調用方會使計時器在其計劃的啟動日期當天或之后啟動。觸發后,計時器調用其關聯的處理程序例程,該例程是指定對象上的選擇器。調用方保留計時器。要從安裝計時器的所有運行循環模式中刪除計時器,需要向計時器發送invalidate消息。

參數 :

timer :要向調用方注冊的計時器。

mode :添加計時器的模式。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 2018.4.8,周日,倒計時60天 想當初決定租房陪讀時,感覺兩年時間好漫長,現在一轉眼就只剩下60天了,前段時...
    追夢者于多多閱讀 1,927評論 5 13
  • iOS 的倒計時有多種實現細節,Cocoa Touch 為我們提供了 NSTimer 類和 GCD 的dispat...
    waylen閱讀 6,738評論 36 44
  • 相信大家在項目里面不少會用到倒計時操作吧,倒計時功能在我們業務開發中使用概率非常高,例如用戶操作姿勢錯誤,我們給...
    Scus閱讀 10,035評論 0 3
  • 背景 前端頁面倒計時功能在很多場景中會用到,如運營活動開始倒計時和活動結束倒計時,又如購物網站的秒殺倒計時,搶購倒...
    kangaroo_v閱讀 3,219評論 2 7
  • 1 那是我初戀 當時感覺有他在 整個世界都是粉紅的 都是甜的 我們一起放學回家 偶爾會在回家路上的小攤 坐下吃東西...
    讀書館閱讀 258評論 0 0