YYFPSLabel
是一个查看当前屏幕帧数的小工具
大致原理
- CADisplayLink 默认每秒 60次;
- 将 CADisplayLink add 到 mainRunLoop 中;
- 使用 CADisplayLink 的 timestamp 属性,在 CADisplayLink 每次 tick 时,记录上一次的 timestamp;
- 用 _count 记录 CADisplayLink tick 的执行次数;
- 计算此次 tick 时, CADisplayLink 的当前 timestamp 和 _lastTimeStamp 的差值;
- 如果差值大于1,fps = _count / delta,计算得出 FPS 数
CADisplayLink小演示
[[CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkAction:)] addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
- (void)displayLinkAction:(CADisplayLink *)link {
static NSTimeInterval lastTime = 0;
static NSInteger frameCount = 0;
if (lastTime == 0) {
lastTime = link.timestamp;
return;
}
frameCount ++;
NSTimeInterval paseTime = link.timestamp - lastTime;
if (paseTime > 1) {
NSInteger fps = frameCount / paseTime;
lastTime = link.timestamp;
frameCount = 0;
NSLog(@"%ld",fps);
}
}
CADisplayLink
CADisplayLink是一个定时器,允许你的应用以和屏幕刷新率相同的频率将内容显示到屏幕上
在应用中创建一个新的 CADisplayLink 对象,并给它提供一个 target 和selector,当屏幕刷新的时候会调用。为了同步显示内容,需要使用add(to:forMode:)方法把它添加到runloop中
一但 CADisplayLink 以特定的模式注册到runloop之后,每当屏幕内容需要刷新的时候,runloop就会调用CADisplayLink绑定的target上的selector,这时target可以读到 CADisplayLink 的每次调用的时间戳,该时间戳是上一帧显示的时间,这样可以用来准备下一帧显示需要的数据
例如应用中播放视频,可能使用时间戳来计算下一帧要显示的视频数据。应用能够利用时间戳来确定下一帧在哪里显示对象
duration属性提供了每帧之间的时间,也就是屏幕每次刷新之间的的时间。为了计算实际的帧率时间,应该使用targetTimestamp - timestamp。可以使用这个值来计算帧率的显示,即近似的计算出下一帧要显示的值
当把CADisplayLink对象add到runloop中后,selector就能被周期性调用,类似于NSTimer被启动了;执行invalidate操作时,CADisplayLink对象就会从runloop中移除,selector调用也随即停止,类似于NSTimer的invalidate方法
CADisplayLink 与 NSTimer
- 原理不同
CADisplayLink是一个能让我们以和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息, CADisplayLink类对应的selector就会被调用一次。
NSTimer以指定的模式注册到runloop后,每当设定的周期时间到达后,runloop会向指定的target发送一次指定的selector消息
- 周期设置方式不同
iOS设备的屏幕刷新频率(FPS)是60Hz,因此CADisplayLink的selector默认调用周期是每秒60次,这个周期可以通过frameInterval属性设置,CADisplayLink的selector每秒调用次数=60/frameInterval。比如当frameInterval设为2,每秒调用就变成30次。因此,CADisplayLink周期的设置方式略显不便。
NSTimer的selector调用周期可以在初始化时直接设定,相对就灵活的多
- 精确度不同
iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。
NSTimer的精确度就显得低了点,比如NSTimer的触发时间到的时候,runloop如果在忙于别的调用,触发时间就会推迟到下一个runloop周期。更有甚者,在OS X v10.9以后为了尽量避免在NSTimer触发时间到了而去中断当前处理的任务,NSTimer新增了tolerance属性,让用户可以设置可以容忍的触发的时间范围
- 使用场合
从原理上不难看出,CADisplayLink使用场合相对专一,适合做界面的不停重绘,比如视频播放的时候需要不停地获取下一帧用于界面渲染。
NSTimer的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用