CADisplayLink

一直以來都想好好學(xué)習(xí)下CoreAnimation,奈何涉及的東西太多,想要一次性全部搞定時間上不允許,以后會斷斷續(xù)續(xù)的補全。最近項目里用到了CADisplayLink,就順便花點時間看了看。

一、簡介

1、所在框架

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

2、功能

CADisplayLink最主要的特征是能提供一個周期性的調(diào)用我們賦給它的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;

}

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

二、特性

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

1、原理不同

CADisplayLink是一個能讓我們以和屏幕刷新率同步的頻率將特定的內(nèi)容畫到屏幕上的定時器類。 CADisplayLink以特定模式注冊到runloop后, 每當(dāng)屏幕顯示內(nèi)容刷新結(jié)束的時候,runloop就會向 CADisplayLink指定的target發(fā)送一次指定的selector消息,??CADisplayLink類對應(yīng)的selector就會被調(diào)用一次。

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

2、周期設(shè)置方式不同

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

NSTimer的selector調(diào)用周期可以在初始化時直接設(shè)定,相對就靈活的多。

3、精確度不同

iOS設(shè)備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會在每次刷新結(jié)束都被調(diào)用,精確度相當(dāng)高。

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

4、使用場合

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

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

三、重要屬性

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

1、 frameInterval

可讀可寫的NSInteger型值,標(biāo)識間隔多少幀調(diào)用一次selector方法,默認值是1,即每幀都調(diào)用一次。官方文檔中強調(diào),當(dāng)該值被設(shè)定小于1時,結(jié)果是不可預(yù)知的。

2、duration

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

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

3、timestamp

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

打印timestamp值,其樣式類似于:

179699.631584

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

CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil];

NSLog("localLayerTime:%f",localLayerTime);

四、注意

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

1、CPU的空閑程度

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

2、執(zhí)行回調(diào)方法所用的時間

如果執(zhí)行回調(diào)時間大于重繪每幀的間隔時間,就會導(dǎo)致跳過若干次回調(diào)調(diào)用機會,這取決于執(zhí)行時間長短。

五、參考文檔

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容