前言
在最近的項目開發過程中,遇到了需要運用定時器的需求,在以前的項目中,也沒用過定時器。最近做的一個項目很有幾個地方用到了定時器,短信驗證碼倒計時、倒計時取消訂單,定時網絡請求。在查閱相關資料過后,也解決了項目中的需求。下面介紹下幾種定時器的用法吧!
CADisplayLink
CADisplayLink是一個能讓我們以和屏幕刷新率相同的頻率將內容畫到屏幕上的定時器。我們在應用中創建一個新的 CADisplayLink 對象,把它添加到一個runloop中,并給它提供一個 target 和selector 在屏幕刷新的時候調用。
- 創建
/** < 創建CADisplayLink > */
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(printSeconds)];
/** < 設置每秒刷新一次 The default value is 60 > */
self.displayLink.preferredFramesPerSecond = 1;
/** < 注冊到RunLoop中 NSDefaultRunLoopMode > */
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
/** < 暫停定時器 Initial state is
false > */
self.displayLink.paused = YES;
- 暫停
self.displayLink.paused = YES;
- 開始
self.displayLink.paused = NO;
- 銷毀
/** < 銷毀定時器 > */
[self.displayLink invalidate];
self.displayLink = nil;
最后
CADisplayLink相比NSTimer來說,精度要高的多,如果有想更深入的了解可以查看官方文檔或相關博客(CADisplayLink)介紹的很詳細。
NSTimer
在最近開發的項目中,用NSTimer實現了定時請求接口,后臺服務器要對前端App狀態進行檢測,要求App在用戶登錄的狀態下,每30s請求一次接口,以便后臺更好的處理先關業務邏輯。在App中只處理了在前臺的情況,App處于后臺,NSTimer會處于掛起狀態,不執行,除非申請后臺執行代碼的權限。下面介紹NSTimer的基本使用方法。
- NSTimer創建
常用的有兩種創建方法,區別是前者需手動加入RunLoop,后者自動將
timer加入到當前線程的RunLoop中
//
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
//
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
Block方法,iOS 10新出的API,使用這個兩個方法,要考慮到兼容性問題
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
其它創建方法請參考頭文件方法聲明
timerWithTimeInterval
- 創建
self.timer = [NSTimer timerWithTimeInterval:1.f target:self selector:@selector(printSeconds) userInfo:nil repeats:YES];
- TimeInterval:執行之前等待的時間。比如設置成1.0,就代表1秒后執行方法
- target:需要執行方法的對象
- selector:需要執行的方法
- repeats:是否需要循環
- 添加到Runloop(注意:上面這種方法創建的定時器必須添加到Runloop,否則定時器不會執行)
/**
< Default mode(NSDefaultRunLoopMode)
默認模式中幾乎包含了所有輸入源(NSConnection除外),一般情況下應使用此模式。
Connection mode(NSConnectionReplyMode)
處理NSConnection對象相關事件,系統內部使用,用戶基本不會使用。
Modal mode(NSModalPanelRunLoopMode)
處理modal panels事件。
Event tracking mode(UITrackingRunLoopMode)
在拖動loop或其他user interface tracking loops時處于此種模式下,在此模式下會限制輸入事件的處理。例如,當手指按住UITableView拖動時就會處于此模式。
Common mode(NSRunLoopCommonModes)
這是一個偽模式,其為一組run loop mode的集合,將輸入源加入此模式意味著在Common Modes中包含的所有模式下都可以處理。在Cocoa應用程序中,默認情況下Common Modes包含default modes,modal modes,event Tracking modes.可使用CFRunLoopAddCommonMode方法想Common Modes中添加自定義modes。
> */
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
scheduledTimerWithTimeInterval
/** < 第二種創建方法 自動加入當前線程的RunLoop中,如果想讓定時器不受滾動視圖影響 應設置Mode為:NSRunLoopCommonModes > */
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.f target:self selector:@selector(printSeconds) userInfo:nil repeats:YES];
// [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
- 暫停、開始定時器
/** < 開始定時器 > */
if (self.timer.isValid) {
self.timer.fireDate = [NSDate date];
}
/** < 暫停定時器 > */
if (self.timer.isValid) {
self.timer.fireDate = [NSDate distantFuture];
}
- 銷毀定時器
[self.timer invalidate];
self.timer = nil;
GCD定時器
在項目中,短信驗證碼倒計時,和訂單定時取消,都用到了GCD定時器,GCD定時器相對來說更為精準,但創建起來稍微麻煩點,下面就介紹基本用法吧!
- 創建
//獲取隊列,這里獲取全局隊列(tips:可以單獨創建一個隊列跑定時器)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//創建定時器(dispatch_source_t本質還是個OC對象)
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//start參數控制計時器第一次觸發的時刻,延遲0s
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, 0 * NSEC_PER_SEC);
// dispatch_time_t start = dispatch_walltime(NULL, 0);
//每隔1s執行一次
uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
dispatch_source_set_timer(self.timer, start, interval, 0);
dispatch_source_set_event_handler(self.timer, ^{
//要執行的任務
});
//開始執行定時器
dispatch_resume(self.timer);
- 開始定時器
dispatch_resume(self.timer);
- 暫停定時器
dispatch_suspend(self.timer);
- 取消定時器
dispatch_cancel(self.timer);
self.timer = nil;
總結
公司的項目剛剛上線,稍微可以松動一下,自己花時間整理了一下定時器的實現方式,除了CADisplayLink,后兩種定時器在項目中都用到了。使用的時候要注意定時器和Runloop之間的聯系、以及定時器的銷毀問題。我也是查閱了相關資料和結合項目中的實際應用整理出來的,如果有寫的不對的地方,歡迎大家批評指正。希望文章能給需要的人有所幫助。