iOS中的定時器

iOS中定時器有三種,分別是NSTimer、CADisplayLink、dispatch_source,下面就分別對這三種計時器進行說明

一、NSTimer

  1. 創建方法
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(action:) userInfo:nil repeats:NO];

TimerInterval: 執行之前等待的時間。比如設置成1.0,就代表1秒后執行方法
target: 需要執行方法的對象。
selector : 需要執行的方法
repeats : 是否需要循環

  1. 釋放方法
[timer invalidate];
timer = nil;

注意 :
調用創建方法后,target對象的計數器會加1,直到執行完畢,自動減1。如果是循環執行的話,就必須手動關閉,否則可以不執行釋放方法。

  1. 特性
  • 存在延遲
    不管是一次性的還是周期性的timer的實際觸發事件的時間,都會與所加入的RunLoopRunLoop Mode有關,如果此RunLoop正在執行一個連續性的運算,timer就會被延時出發。重復性的timer遇到這種情況,如果延遲超過了一個周期,則會在延時結束后立刻執行,并按照之前指定的周期繼續執行。

  • 必須加入Runloop
    使用上面的創建方式,會自動把timer加入MainRunloopNSDefaultRunLoopMode中。如果使用以下方式創建定時器,就必須手動加入Runloop:

NSTimer *timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

二、CADisplayLink

  1. 創建方法
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];    
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  1. 停止方法
[self.displayLink invalidate];  
self.displayLink = nil;

當把CADisplayLink對象addrunloop中后,selector就能被周期性調用,類似于重復的NSTimer被啟動了;執行invalidate操作時,CADisplayLink對象就會從runloop中移除,selector調用也隨即停止,類似于NSTimerinvalidate方法。

  1. 特性
  • 屏幕刷新時調用
    CADisplayLink是一個能讓我們以和屏幕刷新率同步的頻率將特定的內容畫到屏幕上的定時器類。CADisplayLink以特定模式注冊到runloop后,每當屏幕顯示內容刷新結束的時候,runloop就會向CADisplayLink指定的target發送一次指定的selector消息, CADisplayLink類對應的selector就會被調用一次。所以通常情況下,按照iOS設備屏幕的刷新率60次/秒

    • 延遲
      iOS設備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會在每次刷新結束都被調用,精確度相當高。但如果調用的方法比較耗時,超過了屏幕刷新周期,就會導致跳過若干次回調調用機會。
      如果CPU過于繁忙,無法保證屏幕60次/秒的刷新率,就會導致跳過若干次調用回調方法的機會,跳過次數取決CPU的忙碌程度。
  1. 使用場景
    從原理上可以看出,CADisplayLink適合做界面的不停重繪,比如視頻播放的時候需要不停地獲取下一幀用于界面渲染。

  2. 重要屬性

  • frameInterval
    NSInteger類型的值,用來設置間隔多少幀調用一次selector方法,默認值是1,即每幀都調用一次。

  • duration
    readOnlyCFTimeInterval值,表示兩次屏幕刷新之間的時間間隔。需要注意的是,該屬性在targetselector被首次調用以后才會被賦值。selector的調用間隔時間計算方式是:調用間隔時間 = duration × frameInterval。

三、dispatch_source

  1. 創建方法
//需要將dispatch_source_t timer設置為成員變量,不然會立即釋放
@property (nonatomic, strong) dispatch_source_t timer;

 //定時器開始執行的延時時間
NSTimeInterval delayTime = 3.0f;
//定時器間隔時間
NSTimeInterval timeInterval = 3.0f;  
//創建子線程隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//使用之前創建的隊列來創建計時器
   _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//設置延時執行時間,delayTime為要延時的秒數
   dispatch_time_t startDelayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayTime * NSEC_PER_SEC));
//設置計時器
   dispatch_source_set_timer(_timer, startDelayTime, timeInterval * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);
   dispatch_source_set_event_handler(_timer, ^{
        //執行事件
    });
   // 啟動計時器
   dispatch_resume(_timer);
  1. 停止方法
dispatch_source_cancel(_timer);
  1. 特性
  • 默認是重復執行的,可以在事件響應回調中通過dispatch_source_cancel方法來設置為只執行一次,如下代碼:
dispatch_source_set_event_handler(_timer, ^{
         //執行事件
         dispatch_source_cancel(_timer);
 });```
4. 重要屬性

dispatch_source_set_timer(dispatch_source_t source,
dispatch_time_t start,
uint64_t interval,
uint64_t leeway);

 * start
計時器起始時間,可以通過`dispatch_time`創建,如果使用`DISPATCH_TIME_NOW`,則創建后立即執行
 * interval
計時器間隔時間,可以通過`timeInterval * NSEC_PER_SEC`來設置,其中,
`timeInterval`為對應的秒數
 * leeway
這個參數的理解,我覺得[http://www.dreamingwish.com](http://www.dreamingwish.com)上Seven's
同學的解釋很直觀也很易懂:“這個參數告訴系統我們需要計時器觸發的精準程度。所有的計時器都不會保證100%精準,這個參數用來告訴系統你希望系統保證精準的努力程度。如果你希望一個計時器沒五秒觸發一次,并且越準越好,那么你傳遞0為參數。另外,如果是一個周期性任務,比如檢查email,那么你會希望每十分鐘檢查一次,但是不用那么精準。所以你可以傳入60,告訴系統60秒的誤差是可接受的。這樣有什么意義呢?簡單來說,就是降低資源消耗。如果系統可以讓cpu休息足夠長的時間,并在每次醒來的時候執行一個任務集合,而不是不斷的醒來睡去以執行任務,那么系統會更高效。如果傳入一個比較大的leeway給你的計時器,意味著你允許系統拖延你的計時器來將計時器任務與其他任務聯合起來一起執行。
5. 優點:
 * 時間準確
 * 可以使用子線程,解決定時間跑在主線程上卡UI問題
6. 注意事項:
 需要將dispatch_source_t timer設置為成員變量,不然會立即釋放

#####參考:
[控制了時間,就控制了一切!-iOS中幾種定時器](http://www.lxweimin.com/p/21d351116587)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 定時器是開發中常用一中工具,定時器常用的為NSTimer,CADisplayLink以及GCD定時器 NSTime...
    落雪無痕_t閱讀 1,868評論 0 5
  • 在軟件開發過程中,我們常常需要在某個時間后執行某個方法,或者是按照某個周期一直執行某個方法。在這個時候,我們就需要...
    誰遇而安閱讀 20,966評論 2 20
  • 調用一次計時器方法: [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片 myTime...
    3ad997c871e9閱讀 738評論 0 1
  • Run loop 剖析:Runloop 接收的輸入事件來自兩種不同的源:輸入源(intput source)和定時...
    Mitchell閱讀 12,480評論 17 111
  • 我兒,今天你的孩子終于出生了,當看著你滿眼慈愛地看著他(她)的時候,我在后面默默地祝福你,默默地為你高興,我最心愛...
    種樹老頭閱讀 280評論 3 2