Swift中使用CADisplayLink測試APP的FPS(附邏輯說明)

樑華建發表於2019-04-22

我們的目的是測試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
    }
    */

}

複製程式碼

相關文章