源博客地址:以前雖說使用CADisplayLink但是見到這篇博客總結的很詳細,而自己學習知識最有效的方式就是做筆記,所以按照自己方式重新整理學習。
CADisplayLink是一個能讓我們以和屏幕刷新率相同的頻率將內容畫到屏幕上的定時器。我們在應用中創建一個新的CADisplayLink對象,把它添加到一個runloop中,并給它提供一個target和selector在屏幕刷新的時候調用。
一但CADisplayLink以特定的模式注冊到runloop之后,每當屏幕需要刷新的時候,runloop就會調用CADisplayLink綁定的target上的selector,這時target可以讀到CADisplayLink的每次調用的時間戳,用來準備下一幀顯示需要的數據。例如一個視頻應用使用時間戳來計算下一幀要顯示的視頻數據。在UI做動畫的過程中,需要通過時間戳來計算UI對象在動畫的下一幀要更新的大小等等。
在添加進runloop的時候我們應該選用高一些的優先級,來保證動畫的平滑。可以設想一下,我們在動畫的過程中,runloop被添加進來了一個高優先級的任務,那么,下一次的調用就會被暫停轉而先去執行高優先級的任務,然后在接著執行CADisplayLink的調用,從而造成動畫過程的卡頓,使動畫不流暢
CADisplayLink提供了四個方法及四個屬性,如下所示:
方法
//創建定時器
+ (CADisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel;
//添加到RunLoop中
- (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSString *)mode;
//從RunLoop中移除
- (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSString *)mode;
//用于注銷定時使用
- (void)invalidate;
屬性
@property(readonly, nonatomic) CFTimeInterval timestamp;
@property(readonly, nonatomic) CFTimeInterval duration;
@property(getter=isPaused, nonatomic) BOOL paused;
@property(nonatomic) NSInteger frameInterval;
- ** timestamp:**只讀屬性,表示屏幕顯示上一幀的時間戳,這個屬性通常被target用來計算下一幀中應該顯示的內容。打印timestamp值,其樣式類似于:179699.631584。
- ** duration:只讀屬性,表示屏幕每次刷新之間的的時間間隔,是個固定值,該屬性在target的selector被首次調用以后才會被賦值。但是selector的調用間隔時間**計算方式是:時間=duration×frameInterval,我們可以使用這個時間來計算出下一幀要顯示的UI的數值。但是duration只是個大概的時間,如果CPU忙于其它計算,就沒法保證以相同的頻率執行屏幕的繪制操作,這樣會跳過幾次調用回調方法的機會。
- ** frameInterval:**可讀可寫的NSInteger型值,標識間隔多少幀調用一次selector方法,默認值是1,即每幀都調用一次。如果每幀都調用一次的話,對于iOS設備來說那刷新頻率就是60HZ也就是每秒60次,如果將frameInterval設為2那么就會兩幀調用一次,也就是變成了每秒刷新30次。
- ** pause:**控制CADisplayLink的運行。當我們想結束一個CADisplayLink的時候,應該調用-(void)invalidate從runloop中刪除并刪除之前綁定的target跟selector。
代碼示例:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong) CADisplayLink *displayLink;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkSel)];
self.displayLink = displayLink;
displayLink.frameInterval = 2;
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void) displayLinkSel{
NSLog(@"I'm here %f",self.displayLink.duration);
}
@end
執行結果:
2016-09-29 14:48:44.555 CADisplayLink測試[6851:3406626] I'm here 0.016667
2016-09-29 14:48:44.588 CADisplayLink測試[6851:3406626] I'm here 0.016634
2016-09-29 14:48:44.622 CADisplayLink測試[6851:3406626] I'm here 0.016632
2016-09-29 14:48:44.655 CADisplayLink測試[6851:3406626] I'm here 0.016705
2016-09-29 14:48:44.688 CADisplayLink測試[6851:3406626] I'm here 0.016706
2016-09-29 14:48:44.722 CADisplayLink測試[6851:3406626] I'm here 0.016667
2016-09-29 14:48:44.755 CADisplayLink測試[6851:3406626] I'm here 0.016669
說明:
由最后數據可是知道:
1 .selector的調用間隔時間計算方式是:時間=duration×frameInterval
2 .self.displayLink.duration約等于1s/60=0.016秒即16毫秒