You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在iOS ProMotion设备上获取帧率并区分CADisplayLink回调卡顿与帧率切换

如何在iOS ProMotion设备上获取帧率并区分CADisplayLink回调卡顿与帧率切换

嘿,这个问题确实是ProMotion设备做性能监控时的棘手难题——毕竟系统动态切换帧率时,CADisplayLink的回调间隔变化和卡顿导致的延迟看起来几乎一样。结合你提到的iOS 15的特殊情况,我来分享几个实际验证过的可行思路:

  • 利用preferredFrameRateRange的min/max结合实际帧间隔判断
    虽然iOS 15里CADisplayLink.preferredFrameRateRange.preferred会返回0,但minimum和maximum字段是实时更新的,能反映当前系统允许的帧率范围。你可以这么做:

    1. 每次回调时,用当前帧的timestamp减去上一帧的timestamp,计算出实际帧间隔,再转换成实际帧率(1 / 帧间隔)。
    2. 对比当前的minimum和maximum值:如果实际帧率落在这个范围附近(可以加±1的容错,避免微小波动误判),那就是系统在切换帧率档位;如果实际帧率远低于minimum,那大概率是卡顿。
  • 通过连续帧的稳定性辅助判断
    有时候单帧的间隔波动可能是系统帧率切换的过渡,这时候可以多记录几帧的间隔:

    • 如果连续2-3帧的间隔都稳定在某个新的帧率对应的数值,且和当前min/max范围匹配,就判定为帧率切换。
    • 如果连续多帧间隔都远超当前范围的预期值,再判定为卡顿,这样能减少误判。
  • 附一段参考代码示例

    class FramePerformanceMonitor {
        private var displayLink: CADisplayLink?
        private var lastTimestamp: CFTimeInterval = 0
        // 记录连续帧的间隔,用于辅助判断
        private var recentFrameIntervals = [CFTimeInterval]()
        
        func startMonitoring() {
            displayLink = CADisplayLink(target: self, selector: #selector(onDisplayLinkTick(_:)))
            displayLink?.add(to: .main, forMode: .common)
        }
        
        func stopMonitoring() {
            displayLink?.invalidate()
            displayLink = nil
        }
        
        @objc private func onDisplayLinkTick(_ link: CADisplayLink) {
            guard lastTimestamp > 0 else {
                lastTimestamp = link.timestamp
                return
            }
            
            let currentInterval = link.timestamp - lastTimestamp
            lastTimestamp = link.timestamp
            
            // 维护最近3帧的间隔记录
            recentFrameIntervals.append(currentInterval)
            if recentFrameIntervals.count > 3 {
                recentFrameIntervals.removeFirst()
            }
            
            let actualFps = 1 / currentInterval
            let frameRange = link.preferredFrameRateRange
            let minAllowedFps = frameRange.minimum
            let maxAllowedFps = frameRange.maximum
            
            // 计算最近帧的平均帧率
            let avgInterval = recentFrameIntervals.reduce(0, +) / Double(recentFrameIntervals.count)
            let avgFps = 1 / avgInterval
            
            // 判断是否是帧率切换:平均帧率落在允许范围内,且单帧波动小
            let isFrameRateShift = avgFps >= minAllowedFps - 1 && avgFps <= maxAllowedFps + 1
            
            if isFrameRateShift {
                print("系统切换帧率:当前平均帧率 \(avgFps),允许范围 \(minAllowedFps)-\(maxAllowedFps)")
            } else {
                print("出现卡顿:当前平均帧率 \(avgFps),远低于允许范围最小值 \(minAllowedFps)")
            }
        }
    }
    
  • 注意事项

    • ProMotion设备的帧率范围是动态变化的,比如显示静态内容时可能降到10Hz左右,滑动时回升到120Hz,每次回调都要实时获取最新的min/max值。
    • 容错范围可以根据自己的监控需求调整,比如对游戏类应用可以把容错调小,对普通应用可以适当放宽。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 12:19:52