YTPlayerView加载后无法稳定更新视频时长问题求助
问题分析与修复方案
嘿,我一眼就看到几个踩坑点,这就是你标签偶尔不更新的原因,咱们一个个捋清楚:
核心问题:全局变量和UITableView复用机制冲突
你在代码里用了全局的cell和YTPlayer变量来存储当前cell,这完全违背了UITableView的复用逻辑!UITableView会循环利用cell,当playerViewDidBecomeReady回调触发时,那个全局变量里的cell大概率已经被复用给其他行的视频了,你更新的根本不是你想要的那个cell!
其他细节问题
updateLabel方法的冗余与类型错误- 你明明传了
videoView参数,却又通过tag重新获取一遍,完全没必要还容易出错 videoView?.duration()返回的是Double?类型,你直接赋值给需要String类型的cell.textLabel.text,这不仅编译会报错,就算勉强运行也显示不出正常的时长格式
- 你明明传了
无法定位回调对应的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
相关产品推荐
相关产品推荐

