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

YTPlayerView加载后无法稳定更新视频时长问题求助

问题分析与修复方案

嘿,我一眼就看到几个踩坑点,这就是你标签偶尔不更新的原因,咱们一个个捋清楚:

核心问题:全局变量和UITableView复用机制冲突

你在代码里用了全局的cell和YTPlayer变量来存储当前cell,这完全违背了UITableView的复用逻辑!UITableView会循环利用cell,当playerViewDidBecomeReady回调触发时,那个全局变量里的cell大概率已经被复用给其他行的视频了,你更新的根本不是你想要的那个cell!

其他细节问题

  1. updateLabel方法的冗余与类型错误

    • 你明明传了videoView参数,却又通过tag重新获取一遍,完全没必要还容易出错
    • videoView?.duration()返回的是Double?类型,你直接赋值给需要String类型的cell.textLabel.text,这不仅编译会报错,就算勉强运行也显示不出正常的时长格式
  2. 无法定位回调对应的cell
    代理触发时,你没有任何标记能关联到当前视频对应的表格行,自然没法精准更新目标标签


修复步骤

1. 删掉全局的cell和YTPlayer变量

绝对不要用全局变量保存cell,这和UITableView的复用机制天生冲突。

2. 给YTPlayerView绑定对应的indexPath

我们可以通过关联对象,给每个YTPlayerView绑定它所在的indexPath,这样回调时就能找到对应的cell:

import ObjectiveC

private var IndexPathAssociatedKey: UInt8 = 0

extension YTPlayerView {
    var indexPath: IndexPath? {
        get {
            return objc_getAssociatedObject(self, &IndexPathAssociatedKey) as? IndexPath
        }
        set {
            objc_setAssociatedObject(self, &IndexPathAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

然后在cellForRowAt里给videoView绑定indexPath:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cellId = Utils.isIpad() ? "iPadVideosCell" : "videosCell"
    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
    
    if let videoView = cell.viewWithTag(5) as? YTPlayerView {
        videoView.delegate = self
        videoView.indexPath = indexPath // 绑定当前行的indexPath
        // 这里加载你的视频,例如 videoView.load(withVideoId: yourVideoId)
    }
    
    return cell
}

3. 修改代理回调,精准更新目标cell

在playerViewDidBecomeReady里,通过绑定的indexPath找到正确的cell,再更新时长标签:

func playerViewDidBecomeReady(_ playerView: YTPlayerView) {
    print("player is ready to play")
    
    // 确保能找到对应的indexPath和屏幕上的cell
    guard let indexPath = playerView.indexPath,
          let targetCell = tableView.cellForRow(at: indexPath) else {
        return // 如果cell已经被复用或不在屏幕上,直接跳过
    }
    
    updateDurationLabel(for: targetCell, with: playerView)
}

private func updateDurationLabel(for cell: UITableViewCell, with playerView: YTPlayerView) {
    guard let durationSeconds = playerView.duration() else {
        cell.textLabel?.text = "时长未知"
        return
    }
    
    // 把秒数格式化成友好的时分秒格式
    let hours = Int(durationSeconds) / 3600
    let minutes = (Int(durationSeconds) % 3600) / 60
    let seconds = Int(durationSeconds) % 60
    
    let durationText: String
    if hours > 0 {
        durationText = String(format: "%02d:%02d:%02d", hours, minutes, seconds)
    } else {
        durationText = String(format: "%02d:%02d", minutes, seconds)
    }
    
    cell.textLabel?.text = durationText
}

4. 处理cell复用的额外问题

为了避免旧的代理回调影响复用后的cell,建议在cell复用前重置状态:
如果用的是自定义cell,重写prepareForReuse方法:

class VideoTableViewCell: UITableViewCell {
    override func prepareForReuse() {
        super.prepareForReuse()
        
        if let videoView = viewWithTag(5) as? YTPlayerView {
            videoView.delegate = nil
            videoView.indexPath = nil
            videoView.stopVideo() // 可选,根据你的需求决定是否停止播放
            textLabel?.text = "" // 重置标签内容
        }
    }
}

内容的提问来源于stack exchange,提问作者Danutha Fernando

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:04:40