源博客地址:以前虽说使用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毫秒