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

iOS开发:AVPlayer持续获取视频播放时长出现崩溃问题

解决AVPlayer获取播放时长及崩溃问题

咱们先拆解下你代码里的几个核心问题,再一步步给出修复方案:

问题1:NotificationCenter使用完全错误

你把通知的name设为nil,这会监听所有系统通知,完全不是获取实时播放进度的正确姿势。AVPlayer的进度监听官方推荐用周期性时间观察者,NotificationCenter更适合处理播放结束、缓冲状态变更这类一次性事件。

问题2:时长计算逻辑错误

直接取player.currentTime().value是不对的——CMTime的value需要结合timescale才能转换成实际秒数,正确做法是用CMTimeGetSeconds()方法来转换。

问题3:崩溃的根源

你没有在合适时机移除通知观察者,当ViewController被释放后,通知仍会尝试发送给已销毁的实例,直接导致野指针访问(也就是你看到的EXC_BAD_ACCESS错误)。另外如果player是局部变量,也可能提前被释放引发问题。


修复后的完整实现

1. 先声明必要的实例变量

确保player和时间观察者的引用被正确持有:

class YourViewController: UIViewController {
    private var player: AVPlayer?
    private var timeObserverToken: Any? // 保存观察者token,用于后续移除
    // ...其他代码
}

2. 重构视频播放方法

用官方推荐的周期性观察者监听进度,同时正确计算总时长和当前时长:

func videoPlay(){
    guard let videoURL = videoURL else { return }
    
    player = AVPlayer(url: videoURL)
    let playerController = AVPlayerViewController()
    playerController.player = player
    addChild(playerController)
    view.addSubview(playerController.view)
    playerController.view.frame = CGRect(x: 0, y: 20, width: 375, height: 207)
    
    // 添加每秒更新一次的进度观察者
    let updateInterval = CMTimeMakeWithSeconds(1.0, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
    timeObserverToken = player?.addPeriodicTimeObserver(forInterval: updateInterval, queue: .main) { [weak self] currentTime in
        guard let self = self, let player = self.player else { return }
        
        // 转换为实际秒数的当前播放时长
        let currentPlayTime = CMTimeGetSeconds(currentTime)
        // 转换为实际秒数的视频总时长
        let totalVideoDuration = CMTimeGetSeconds(player.currentItem?.duration ?? .zero)
        
        print("当前播放时长:\(currentPlayTime),视频总时长:\(totalVideoDuration)")
    }
    
    player?.play()
    
    if player?.rate != 0 && player?.error == nil {
        print("video player is playing.................")
    } else {
        print("video player is NOT playing.")
    }
}

3. 移除观察者避免崩溃

在ViewController销毁时清理观察者,防止内存泄漏和野指针:

deinit {
    // 移除时间观察者
    if let token = timeObserverToken {
        player?.removeTimeObserver(token)
    }
    // 顺带清理之前添加的所有通知观察者
    NotificationCenter.default.removeObserver(self)
}

额外小贴士

  • 要是需要监听视频总时长的动态变化(比如直播流时长更新),可以额外监听AVPlayerItem.durationDidChangeNotification通知,在回调里更新总时长。
  • 用[weak self]是为了避免循环引用,保证ViewController能被正常销毁。

内容的提问来源于stack exchange,提问作者Vishal Parmar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:30:52