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

AVPlayerViewController仅发声无画面,present调用报错求助

问题分析与解决方案

核心问题

  1. UITableViewCell 不属于 UIViewController 类型,因此没有 present 方法,直接调用 self.present 会触发报错。
  2. 通过 self.window?.rootViewController?.present 弹出播放器时出现有声音无画面,是因为单元格生命周期不稳定,直接在Cell中持有并弹出AVPlayerViewController会导致视图层级异常或控制器实例被意外释放。

正确解决方案:将播放逻辑移至ViewController

单元格仅负责触发播放事件,实际的播放器弹出逻辑交给对应的UITableViewController处理,符合iOS开发的职责分离原则。

1. 修改VideoPostCell代码

import UIKit
import AVFoundation
import AVKit

class VideoPostCell: UITableViewCell {
    @IBOutlet weak var thumbnailImageView: UIImageView!
    
    static let identifier: String = "VideoPostCell"
    
    static func nib() -> UINib{
        return UINib(nibName: "VideoPostCell", bundle: nil)
    }
    
    var playURL: URL?
    // 添加闭包,用于通知ViewController触发播放
    var didTapToPlay: ((URL) -> Void)?

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        guard selected, let safeURL = playURL else { return }
        // 触发闭包,传递视频URL
        didTapToPlay?(safeURL)
    }
}

2. 在对应的TableViewController中处理播放

class VideoListViewController: UITableViewController {
    // 假设你的视频URL数组
    var videoURLs: [URL] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(VideoPostCell.nib(), forCellReuseIdentifier: VideoPostCell.identifier)
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: VideoPostCell.identifier, for: indexPath) as! VideoPostCell
        let url = videoURLs[indexPath.row]
        cell.playURL = url
        // 绑定闭包,处理播放逻辑
        cell.didTapToPlay = { [weak self] videoURL in
            let player = AVPlayer(url: videoURL)
            let playerVC = AVPlayerViewController()
            playerVC.player = player
            // 从当前ViewController弹出播放器,确保视图层级正确
            self?.present(playerVC, animated: true) {
                player.play()
            }
        }
        return cell
    }
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 200 // 根据需求调整高度
    }
}

关于self.window?.rootViewController?.present的说明

该方法在当前iOS版本中语法上是可用的,但不推荐使用:

  • 若rootViewController不是当前最上层的控制器(比如存在导航控制器、tabBar控制器或已弹出的弹窗),会导致播放器弹出层级异常。
  • 单元格的生命周期由TableView管理,直接在Cell中持有AVPlayerViewController容易引发内存问题或视图加载异常,这也是你出现有声音无画面的核心原因。

内容的提问来源于stack exchange,提问作者Tony Yao

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 21:09:25