Swift中如何检测AVPlayer已播放达3秒
检测AVPlayer播放满3秒的实现方案
看起来你已经搭建好了UITableViewCell中自动播放视频的基础框架,现在需要精准捕捉视频播放满3秒的时刻对吧?我给你一套可靠的实现方案,结合AVPlayer的时间监听机制来完成这个需求:
第一步:添加必要的属性和清理逻辑
首先在你的PostCell类里添加用于存储时间观察者的属性,同时要确保在单元格复用或销毁时移除观察者,避免内存泄漏:
class PostCell: UITableViewCell { var player: AVPlayer? var playerLayer: AVPlayerLayer? var post: Post? { didSet { updateView() } } // 存储时间观察者的引用,用于后续移除 private var playbackObserver: Any? // 重写prepareForReuse,清理旧的播放状态和观察者 override func prepareForReuse() { super.prepareForReuse() player?.pause() player?.seek(to: .zero) if let observer = playbackObserver { player?.removeTimeObserver(observer) playbackObserver = nil } playerLayer?.removeFromSuperlayer() player = nil playerLayer = nil } // 你的viewcount方法和其他现有代码... func viewcount() { // 你的现有实现 } }
第二步:设置视频播放与3秒时间监听
在updateView方法里,初始化播放器后,添加边界时间观察者(Boundary Time Observer),它会在视频播放到指定的3秒时刻精准触发回调:
func updateView() { self.viewcount() // 先清理旧的播放器和观察者 if let observer = playbackObserver { player?.removeTimeObserver(observer) playbackObserver = nil } playerLayer?.removeFromSuperlayer() player = nil guard let videoUrlString = post?.videoUrl, let videoUrl = URL(string: videoUrlString) else { return } // 初始化播放器和图层 let playerItem = AVPlayerItem(url: videoUrl) player = AVPlayer(playerItem: playerItem) playerLayer = AVPlayerLayer(player: player) playerLayer?.frame = self.contentView.bounds // 根据你的布局调整frame playerLayer?.videoGravity = .resizeAspectFill self.contentView.layer.addSublayer(playerLayer!) // 设置3秒的时间点 let threeSecondTime = CMTimeMakeWithSeconds(3, preferredTimescale: 1) let timeMarkers = [threeSecondTime] // 添加边界时间观察者 playbackObserver = player?.addBoundaryTimeObserver(forTimes: timeMarkers.map { NSValue(time: $0) }, queue: DispatchQueue.main) { [weak self] in // 这里就是视频播放满3秒时触发的回调 guard let self = self else { return } print("视频已播放满3秒!") // 在这里执行你需要的逻辑,比如统计播放时长、触发其他事件等 // 如果只需要触发一次,可以在这里移除观察者 if let observer = self.playbackObserver { self.player?.removeTimeObserver(observer) self.playbackObserver = nil } } }
第三步:配合UITableView的单元格可见性控制播放
为了确保只有可见的单元格才播放视频,在你的UITableView所在的ViewController里实现以下方法:
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let postCell = cell as? PostCell else { return } postCell.player?.play() } override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let postCell = cell as? PostCell else { return } postCell.player?.pause() postCell.player?.seek(to: .zero) }
关键注意点
- 弱引用self:在时间观察者的回调里一定要用
[weak self],避免循环引用导致单元格无法释放。 - 观察者移除:无论单元格复用还是播放到3秒后,都要及时移除观察者,防止重复触发或内存泄漏。
- 时间精度:使用
addBoundaryTimeObserver比周期性的addPeriodicTimeObserver更精准,因为它会在指定的时间点精确触发,适合你需要的“播放满3秒”的检测需求。
内容的提问来源于stack exchange,提问作者Justin Robinson
相关产品推荐
相关产品推荐

