iOS 定時器 NSTimer、CADisplayLink、GCD3種方式的實現

在軟件開發過程中,我們常常需要在某個時間後執行某個方法,或者是按照某個週期一直執行某個方法。在這個時候,我們就需要用到定時器。

然而,在iOS中有很多方法完成以上的任務,到底有多少種方法呢?經過查閱資料,大概有三種方法:NSTimer、CADisplayLink、GCD。接下來我就一一介紹它們的用法。

一、NSTimer

1. 創建方法

1 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(action:) userInfo:nil repeats:NO];
  • TimerInterval : 執行之前等待的時間。比如設置成1.0,就代表1秒後執行方法

  • target : 需要執行方法的對象。

  • selector : 需要執行的方法

  • repeats : 是否需要循環

2. 釋放方法

1 [timer invalidate];
  • 注意 :

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

3. 特性

  • 存在延遲

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

  • 必須加入Runloop

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

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

 

UIScrollView 拖動時執行的是 UITrackingRunLoopMode,會導致暫停定時器,等恢復爲 NSDefaultRunLoopMode 時才恢復定時器。

所以如果需要定時器在 UIScrollView 拖動時也不影響的話,建議添加到 UITrackingRunLoopMode 或 NSRunLoopCommonModes 中:

1 NSTimer *timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
2 [[NSRunLoop mainRunLoop] addTimer:timer forMode: UITrackingRunLoopMode]; ///< 或者 NSRunLoopCommonModes

二、CADisplayLink

1. 創建方法

1 self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];    
2 [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

2. 停止方法

1 [self.displayLink invalidate];  
2 self.displayLink = nil;
3         
4 /**當把CADisplayLink對象add到runloop中後,selector就能被週期性調用,類似於重複的NSTimer被啓動了;執行invalidate操作時,CADisplayLink對象就會從runloop中移除,selector調用也隨即停止,類似於NSTimer的invalidate方法。**/

3. 特性

  • 屏幕刷新時調用

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

  • 延遲

    • iOS設備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會在每次刷新結束都被調用,精確度相當高。但如果調用的方法比較耗時,超過了屏幕刷新週期,就會導致跳過若干次回調調用機會。

    • 如果CPU過於繁忙,無法保證屏幕60次/秒的刷新率,就會導致跳過若干次調用回調方法的機會,跳過次數取決CPU的忙碌程度。

  • 使用場景

    從原理上可以看出,CADisplayLink適合做界面的不停重繪,比如視頻播放的時候需要不停地獲取下一幀用於界面渲染。

4. 重要屬性

  • frameInterval

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

  • duration

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

 

三、GCD方式

  • 執行一次

  • 1 double delayInSeconds = 2.0;
    2 dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
    3 dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    4     //執行事件
    5 });
  • 重複執行

  • 複製代碼
    1 NSTimeInterval period = 1.0; //設置時間間隔
    2 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    3 dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    4 dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒執行
    5 dispatch_source_set_event_handler(_timer, ^{
    6      //在這裏執行事件
    7 });
    8 dispatch_resume(_timer);

    複製代碼

  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)

  

  2.停止方法

dispatch_source_cancel(_timer);

  

  3.重要屬性

 

收藏學習,轉自:

iOS中幾種定時器 - 控制了時間,就控制了一切

iOS中的定時器

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章