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

添加AVPlayer周期性时间观察者后,类似YouTube布局的TableView卡顿

解决AVPlayer周期时间观察者导致TableView冻结的问题

你猜得完全正确!问题根源就是把时间观察者的回调队列指定为DispatchQueue.main了。主队列是负责所有UI渲染和用户交互的核心队列,你的回调每秒触发一次,哪怕只是简单的print操作,也会持续抢占主队列的资源,导致TableView的滚动、刷新这些UI操作得不到足够的执行时间,自然就出现冻结卡顿了。

具体解决方案

  1. 创建专属的后台串行队列
    先给时间观察者单独建一个后台队列,用来处理非UI相关的逻辑,完全避开主队列的资源竞争:
// 自定义队列标签,方便调试时区分
let timeObserverQueue = DispatchQueue(label: "com.yourapp.avplayer.time.callback")
  1. 替换队列并拆分UI与非UI逻辑
    把时间观察者的queue参数换成刚才创建的后台队列,如果后续需要更新UI(比如进度条、时间显示),再通过DispatchQueue.main.async切回主队列执行:
observer = self.avPlayer.addPeriodicTimeObserver(
    forInterval: CMTimeMake(1, 1),
    queue: timeObserverQueue,
    using: { [weak self] time in
        guard let self = self else { return }
        
        // 非UI操作在后台队列执行,不影响主队列
        let currentSeconds = CMTimeGetSeconds(time)
        let totalDuration = self.avPlayer.currentItem?.asset.duration.seconds
        print(currentSeconds, totalDuration)
        
        // 若需更新UI,必须切回主队列
        DispatchQueue.main.async {
            // 示例:更新进度条
            // self.progressBar.progress = Float(currentSeconds / (totalDuration ?? 1))
        }
    }
)

额外的优化要点

  • 防止内存泄漏:回调里一定要用[weak self],避免AVPlayer和当前控制器形成强引用循环,导致对象无法正常销毁。
  • 调整回调频率:如果业务不需要每秒更新一次,可以把时间间隔调大,比如CMTimeMake(1, 2)就是每0.5秒触发一次,减少回调次数。
  • 及时清理观察者:在控制器销毁或者AVPlayer不再使用时,记得移除时间观察者,避免无效回调占用资源:
if let timeObserver = observer {
    self.avPlayer.removeTimeObserver(timeObserver)
    observer = nil
}

内容的提问来源于stack exchange,提问作者Deiby Toralva Baldeón

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:27:51