CADisplayLink

一 簡介

1 所在框架

CADisplayLink和其它CoreAnimation類一樣,都是在QuartzCore.framework里。

2 功能

CADisplayLink最主要的特征是能提供一個周期性的調用我們賦給它的selector的機制,從這點上看它很像定時器NSTimer。

3 使用方式

- (void)startDisplayLink
{
    self.displayLink = [CADisplayLink displayLinkWithTarget:self
         selector:@selector(handleDisplayLink:)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop]
      forMode:NSDefaultRunLoopMode];
}

- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
  //do something
}

- (void)stopDisplayLink
{
    [self.displayLink invalidate];
    self.displayLink = nil;
}

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

特性

下面結合NSTimer來介紹 CADisplayLink,與NSTimer不同的地方有:

1 原理不同

CADisplayLink是一個能讓我們以和屏幕刷新率同步的頻率將特定的內容畫到屏幕上的定時器類。 CADisplayLink以特定模式注冊到runloop后, 每當屏幕顯示內容刷新結束的時候,runloop就會向 CADisplayLink指定的target發送一次指定的selector消息, CADisplayLink類對應的selector就會被調用一次。

NSTimer以指定的模式注冊到runloop后,每當設定的周期時間到達后,runloop會向指定的target發送一次指定的selector消息。

2 周期設置方式不同

iOS設備的屏幕刷新頻率(FPS)是60Hz,因此CADisplayLink的selector 默認調用周期是每秒60次,這個周期可以通過frameInterval屬性設置, CADisplayLink的selector每秒調用次數=60/ frameInterval。比如當 frameInterval設為2,每秒調用就變成30次。因此, CADisplayLink 周期的設置方式略顯不便。

NSTimer的selector調用周期可以在初始化時直接設定,相對就靈活的多。

3 精確度不同

iOS設備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會在每次刷新結束都被調用,精確度相當高。

NSTimer的精確度就顯得低了點,比如NSTimer的觸發時間到的時候,runloop如果在忙于別的調用,觸發時間就會推遲到下一個runloop周期。更有甚者,在OS X v10.9以后為了盡量避免在NSTimer觸發時間到了而去中斷當前處理的任務,NSTimer新增了tolerance屬性,讓用戶可以設置可以容忍的觸發的時間范圍。

4 使用場合

從原理上不難看出, CADisplayLink 使用場合相對專一, 適合做界面的不停重繪,比如視頻播放的時候需要不停地獲取下一幀用于界面渲染。

NSTimer的使用范圍要廣泛的多,各種需要單次或者循環定時處理的任務都可以使用。

三 重要屬性

下面不完整的列出了 CADisplayLink的幾個重要屬性:

1、 frameInterval

可讀可寫的NSInteger型值,標識間隔多少幀調用一次selector方法,默認值是1,即每幀都調用一次。官方文檔中強調,當該值被設定小于1時,結果是不可預知的。

2、duration

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

現存的iOS設備屏幕的FPS都是60Hz,這一點可以從CADisplayLink的duration屬性看出來。duration的值都是0.166666…,即1/60。盡管如此,我們并沒法確定蘋果不會改變 FPS ,如果以后某一天將 FPS 提升到了120Hz了怎么辦呢?這時,你設置了frameInterval屬性值為2期望每秒刷新30次,卻發現每秒刷新了60次,結果可想而知,出于安全考慮,還是先根據duration判斷屏幕的 FPS再去使用 CADisplayLink 。

3、timestamp

只讀的CFTimeInterval值,表示屏幕顯示的上一幀的時間戳,這個屬性通常被target用來計算下一幀中應該顯示的內容。

雖然名為時間戳,但這和常見的unix時間戳差異很大,事實上這是CoreAnimation使用的時間格式。每個CALayer都有一個本地時間(CALayer本地時間的具體作用會在后續文章中說明),可以獲取當前CALayer的本地時間并打印:

CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil];
NSLog("localLayerTime:%f",localLayerTime);

四、注意

iOS并不能保證能以每秒60次的頻率調用回調方法,這取決于:

1、CPU的空閑程度

如果CPU忙于其它計算,就沒法保證以60HZ執行屏幕的繪制動作,導致跳過若干次調用回調方法的機會,跳過次數取決CPU的忙碌程度。

2、執行回調方法所用的時間

如果執行回調時間大于重繪每幀的間隔時間,就會導致跳過若干次回調調用機會,這取決于執行時間長短。

五、參考文檔

1、官方文檔

https://developer.apple.com/library/ios/documentation/QuartzCore/Reference/CADisplayLink_ClassRef/Reference/Reference.html#//apple_ref/doc/uid/TP40009031-CH1-DontLinkElementID_1

2、官方使用CADisplayLink播放視頻的例子

https://developer.apple.com/library/ios/samplecode/AVBasicVideoOutput/Introduction/Intro.html#//apple_ref/doc/uid/DTS40013109

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容