一、簡介
1、所在框架
CADisplayLink和其它CoreAnimation類一樣,都是在QuartzCore.framework里。
2、功能
CADisplayLink最主要的特征是能提供一個(gè)周期性的調(diào)用我們賦給它的selector的機(jī)制,從這點(diǎn)上看它很像定時(shí)器NSTimer。
3、使用方式
- (void)startDisplayLink{
?self.displayLink = ? ? ? [CADisplayLinkdisplayLinkWithTarget:selfselector:@selector(handleDisplayLink:)]; ? ? ? ? ?[self.displayLink addToRunLoop:[NSRunLoopcurrentRunLoop] ? ? ?forMode:NSDefaultRunLoopMode];}- (void)handleDisplayLink: ?(CADisplayLink*)displayLink{//do something
}
- (void)stopDisplayLink{?
?? [self.displayLink invalidate];self.displayLink =nil;
}
當(dāng)把CADisplayLink對(duì)象add到runloop中后,selector就能被周期性調(diào)用,類似于NSTimer被啟動(dòng)了;執(zhí)行invalidate操作時(shí),CADisplayLink對(duì)象就會(huì)從runloop中移除,selector調(diào)用也隨即停止,類似于NSTimer的invalidate方法。
二、特性
下面結(jié)合NSTimer來介紹CADisplayLink,與NSTimer不同的地方有:
1、原理不同
CADisplayLink是一個(gè)能讓我們以和屏幕刷新率同步的頻率將特定的內(nèi)容畫到屏幕上的定時(shí)器類。CADisplayLink以特定模式注冊(cè)到runloop后,每當(dāng)屏幕顯示內(nèi)容刷新結(jié)束的時(shí)候,runloop就會(huì)向CADisplayLink指定的target發(fā)送一次指定的selector消息,CADisplayLink類對(duì)應(yīng)的selector就會(huì)被調(diào)用一次。
NSTimer以指定的模式注冊(cè)到runloop后,每當(dāng)設(shè)定的周期時(shí)間到達(dá)后,runloop會(huì)向指定的target發(fā)送一次指定的selector消息。
2、周期設(shè)置方式不同
iOS設(shè)備的屏幕刷新頻率(FPS)是60Hz,因此CADisplayLink的selector默認(rèn)調(diào)用周期是每秒60次,這個(gè)周期可以通過frameInterval屬性設(shè)置,CADisplayLink的selector每秒調(diào)用次數(shù)=60/frameInterval。比如當(dāng)frameInterval設(shè)為2,每秒調(diào)用就變成30次。因此,CADisplayLink周期的設(shè)置方式略顯不便。
NSTimer的selector調(diào)用周期可以在初始化時(shí)直接設(shè)定,相對(duì)就靈活的多。
3、精確度不同
iOS設(shè)備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會(huì)在每次刷新結(jié)束都被調(diào)用,精確度相當(dāng)高。
NSTimer的精確度就顯得低了點(diǎn),比如NSTimer的觸發(fā)時(shí)間到的時(shí)候,runloop如果在忙于別的調(diào)用,觸發(fā)時(shí)間就會(huì)推遲到下一個(gè)runloop周期。更有甚者,在OS X v10.9以后為了盡量避免在NSTimer觸發(fā)時(shí)間到了而去中斷當(dāng)前處理的任務(wù),NSTimer新增了tolerance屬性,讓用戶可以設(shè)置可以容忍的觸發(fā)的時(shí)間范圍。
4、使用場(chǎng)合
從原理上不難看出,CADisplayLink使用場(chǎng)合相對(duì)專一,適合做界面的不停重繪,比如視頻播放的時(shí)候需要不停地獲取下一幀用于界面渲染。
NSTimer的使用范圍要廣泛的多,各種需要單次或者循環(huán)定時(shí)處理的任務(wù)都可以使用。
三、重要屬性
下面不完整的列出了CADisplayLink的幾個(gè)重要屬性:
1、frameInterval
可讀可寫的NSInteger型值,標(biāo)識(shí)間隔多少幀調(diào)用一次selector方法,默認(rèn)值是1,即每幀都調(diào)用一次。官方文檔中強(qiáng)調(diào),當(dāng)該值被設(shè)定小于1時(shí),結(jié)果是不可預(yù)知的。
2、duration
只讀的CFTimeInterval值,表示兩次屏幕刷新之間的時(shí)間間隔。需要注意的是,該屬性在target的selector被首次調(diào)用以后才會(huì)被賦值。selector的調(diào)用間隔時(shí)間計(jì)算方式是:時(shí)間=duration×frameInterval。
現(xiàn)存的iOS設(shè)備屏幕的FPS都是60Hz,這一點(diǎn)可以從CADisplayLink的duration屬性看出來。duration的值都是0.166666…,即1/60。盡管如此,我們并沒法確定蘋果不會(huì)改變FPS,如果以后某一天將FPS提升到了120Hz了怎么辦呢?這時(shí),你設(shè)置了frameInterval屬性值為2期望每秒刷新30次,卻發(fā)現(xiàn)每秒刷新了60次,結(jié)果可想而知,出于安全考慮,還是先根據(jù)duration判斷屏幕的FPS再去使用CADisplayLink。
3、timestamp
只讀的CFTimeInterval值,表示屏幕顯示的上一幀的時(shí)間戳,這個(gè)屬性通常被target用來計(jì)算下一幀中應(yīng)該顯示的內(nèi)容。
打印timestamp值,其樣式類似于:
179699.631584
雖然名為時(shí)間戳,但這和常見的unix時(shí)間戳差異很大,事實(shí)上這是CoreAnimation使用的時(shí)間格式。每個(gè)CALayer都有一個(gè)本地時(shí)間(CALayer本地時(shí)間的具體作用會(huì)在后續(xù)文章中說明),可以獲取當(dāng)前CALayer的本地時(shí)間并打?。?/p>
CFTimeIntervallocalLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil];NSLog("localLayerTime:%f",localLayerTime);
四、注意
iOS并不能保證能以每秒60次的頻率調(diào)用回調(diào)方法,這取決于:
1、CPU的空閑程度
如果CPU忙于其它計(jì)算,就沒法保證以60HZ執(zhí)行屏幕的繪制動(dòng)作,導(dǎo)致跳過若干次調(diào)用回調(diào)方法的機(jī)會(huì),跳過次數(shù)取決CPU的忙碌程度。
2、執(zhí)行回調(diào)方法所用的時(shí)間
如果執(zhí)行回調(diào)時(shí)間大于重繪每幀的間隔時(shí)間,就會(huì)導(dǎo)致跳過若干次回調(diào)調(diào)用機(jī)會(huì),這取決于執(zhí)行時(shí)間長短。