Swift中使用CADisplayLink测试APP的FPS(附逻辑说明)

1,501 阅读2分钟

我们的目的是测试APP的FPS,而FPS是需要每时每刻都要显示的,我们可以把某个事件添加到RunLoop的commonMode中去一直监听FPS值改变,因为commonMode是一种特殊的mode,会把我们的事件添加到所有的mode中,无论用户在滑动还是停止都会进行该事件监听

苹果提供CADisplayLink,为我们测试屏幕每帧的刷新率,下面是苹果的描述

Class(CADisplayLink) representing a timer bound to the display vsync. *

那现在我们来整理一下思路,为了更友好的显示FPS,我们可以设置一个Label类这样就可以直接展现在屏幕上面了

  • FPSLabel里面需要有几个属性去计算FPS值,首先需要一个CADisplayLink,我们可以在label调用init的时候就把它添加添加到commonMode

  • 我们设置一个lastTime用与计算完这一秒后,下一秒的继续计算(比如计算完第0秒到第1秒为多少帧,我们下次要把lastTime置为第1秒而不是第0秒)

  • 我们设置一个count用来记录一秒内刷新了多少帧

import UIKit

class FPSLabel: UILabel {

    private var link:CADisplayLink?
    
    private var lastTime:TimeInterval = 0.0;
    
    private var count:Int = 0;
    
    override init(frame: CGRect)
    {
        super.init(frame: frame)
        link = CADisplayLink.init(target: self, selector: #selector(FPSLabel.didTick(link:)))
        //commom会无论用户的app处于什么停止还是滑动都会进行fps打印(commonMode会添加timer到所有mode上面)
        //receiver是指didTick方法
        link?.add(to: RunLoop.current, forMode: .common)
    }
    
    required init?(coder aDecoder: NSCoder)
    {
        super.init(coder: aDecoder)
    }
    
    @objc func didTick(link:CADisplayLink) {
        
        if lastTime == 0
        {
            
            lastTime = link.timestamp
            //print("lastTime \(lastTime)")
            return
        }
        //用来记录一秒进入这个方法多少次,如果进入了20次那么count就变成20,20帧
        count += 1
        //在一秒内打印的次数
        let delta = link.timestamp - lastTime
        //print("link.timestamp \(link.timestamp) lastTime\(lastTime)")
        if delta < 1{
            //不够一秒就返回,继续往上面count加一,这样就可以获得一秒内有多少个页面
            return
        }
        //这时候已经到一秒了,我们先把lastTime更新至当前时间以便下一次计算
        lastTime = link.timestamp
        //delta是1.0000000....
        print("delta :\(delta)")
        let fps = Double(count)/delta
        
        count = 0
        
        text = String.init(format: "%02.0f帧", round(fps))
        
        print(text ?? "0")
    }
    
    /*
     Only override draw() if you perform custom drawing.
     An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
         Drawing code
    }
    */

}