iOS定時器-NSTimer、CADisplayLink、GCD

前言

在最近的項目開發過程中,遇到了需要運用定時器的需求,在以前的項目中,也沒用過定時器。最近做的一個項目很有幾個地方用到了定時器,短信驗證碼倒計時、倒計時取消訂單,定時網絡請求。在查閱相關資料過后,也解決了項目中的需求。下面介紹下幾種定時器的用法吧!

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

  1. 創建
self.timer = [NSTimer timerWithTimeInterval:1.f target:self selector:@selector(printSeconds) userInfo:nil repeats:YES];
  • TimeInterval:執行之前等待的時間。比如設置成1.0,就代表1秒后執行方法
  • target:需要執行方法的對象
  • selector:需要執行的方法
  • repeats:是否需要循環
  1. 添加到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之間的聯系、以及定時器的銷毀問題。我也是查閱了相關資料和結合項目中的實際應用整理出來的,如果有寫的不對的地方,歡迎大家批評指正。希望文章能給需要的人有所幫助。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容