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