1. 程式人生 > >NSTimer、CADisplayLink、GCD 三種定時器的用法

NSTimer、CADisplayLink、GCD 三種定時器的用法

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

在iOS中有很多方法完成定時器的任務,例如 NSTimer、CADisplayLink 和 GCD都可以。

一、NSTimer

1. 建立方法


    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(action:) userInfo:nil repeats:NO];

    TimerInterval : 執行之前等待的時間。比如設定成1.0,就代表1秒後執行方法
    target : 需要執行方法的物件。
    selector : 需要執行的方法
    repeats : 是否需要迴圈


2. 釋放方法

    [timer invalidate];

    注意 : 呼叫建立方法後,target物件的計數器會加1,直到執行完畢,自動減1。如果是迴圈執行的話,就必須手動關閉,否則可以不執行釋放方法。


3. 特點

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

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

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


二、CADisplayLink


1. 建立方法

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


2. 停止方法

    [displayLink invalidate];

    displayLink = nil;

    當把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;

    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

    //執行事件

    });


    2. 重複執行

    NSTimeInterval period = 1.0; //設定時間間隔

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

    dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒執行

    dispatch_source_set_event_handler(_timer, ^{

    //在這裡執行事件

    });

    dispatch_resume(_timer);