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
相关产品推荐
相关产品推荐

