使用CADisplayLink编写FPS检测工具

1,292 阅读2分钟

前言

FPS平时接触比较多的相信就是游戏党了,它代表的是刷新频率,刷新频率越高,每秒看到的画面数量越多,屏幕也就越来越清晰,眼睛感觉也就越自然,相反,频率越低,则越卡顿,人眼睛感觉流畅的刷新频率为60帧

而CADisplayLink就与帧率相关的一个组件,与NSTimer类似,区别就是它是每一帧调用一次,来自于QuartzCore框架,可以理解为其可能就是做动画包含的重要控件

源码地址

FPS检测工具实现

主要实现逻辑是使用CADisplayLink开启一个loop,正常来说一秒60帧,也就是调用60次,那么调用次数除以这一秒的开始和结束时间差就是实际帧率FPS

另外,毕竟卡顿的时候1s还是1s,可是loop次数就会响应减少,由于卡顿时间也不会固定在1s的时候调用最后一次

因此:

实际帧率 = 调用次数 / 间隔时间

检测FPS逻辑一共分为下面几个步骤:

1.使用CADisplayLink初始化loop,初始化调用次数count和开始时间参数beginTime,以便于计算帧率

2.计算帧率需要时间段,第一次loop时,保存初始时间,结束准备下一轮,回到步骤1

3.时间的调用次数count + 1

4.计算: 时间间隔 = 本地调用时间 - 开始时间,用调用次数count / 时间间隔就是帧率了(这里如果时间间隔小于1s则不计算,没有实际意义)

5.帧率 = 调用次数 / 时间间隔,可以向上或者向下取整,则就是帧率了

6.初始化调用次数count,更新开始时间为当前时间,开始下一轮FPS的计算

核心代码实现逻辑如下所示:

//开始loop调用
- (void)startMonitor {
    _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(loopLink:)];
    [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
//loop调用回调
- (void)loopLink:(CADisplayLink *)link {
    //开始时间不存在则赋值,并结束,只会走一次
    if (_beginTime == 0) {
        _beginTime = link.timestamp;
        return;
    }
    _count++;
    //不够1s直接结束
    CFTimeInterval delta = link.timestamp - _beginTime; //获取时间间隔
    if (delta < 1) return;
    
    //计算帧率,帧率 = 调用次数 / 时间间隔
    NSInteger fpsCount = _count / delta; //结果直接向下取整
    
    //外界实现回调的话,回调以通知外接帧率
    if (_onUpdateBlock) _onUpdateBlock(fpsCount);
    
    //初始化开始时间和次数,重新开始计算下1s(1s多一点)的帧率
    _beginTime = link.timestamp;
    _count = 0;
}
//移除loop调用,这个就和NSTimer一样了,invalidate会将计时器从所有RunloopMode中移除
- (void)stopMonitor {
    if (_displayLink) {
        [_displayLink invalidate];
        _displayLink = nil;
    }
}

最后

其实现逻辑就这么点了,源码中还加入了FPSLabel的UI界面,可以直接使用,快去试试吧