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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:06:28