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

iOS应用崩溃:尝试模态展示已有父控制器的AVPlayerViewController

问题分析与解决方案

崩溃原因

你遇到的崩溃核心原因有两个:

  1. 重复控制器生命周期操作:在playAbilitiesVideos中同时对AVPlayerViewController执行了present(模态展示)和addChild+view.addSubview(作为子控制器嵌入)操作——同一个视图控制器不能同时被模态展示和添加为子控制器,这会导致系统判定其存在冲突的父控制器关系,触发崩溃。
  2. 过早执行模态操作:在viewDidLoad中调用present时机不合适,此时当前控制器的视图还未完全加入应用的视图层级,模态展示操作的执行条件不满足。

另外代码中还有URL强制解包的隐患:URL(string: agentAbilitiesVideoURL)!如果URL字符串无效会直接崩溃,必须处理可选值。


修复方案

根据你的需求选择以下两种方案之一:

方案一:模态播放(与按钮触发逻辑一致)

保留模态展示的逻辑,移除子控制器相关代码,并将播放操作推迟到视图完全显示后执行:

class AbilitiesDetailsViewController: UIViewController, AVPlayerViewControllerDelegate {

    @IBOutlet var skillDetailsLabel: UILabel!
    @IBOutlet var skillNameLabel: UILabel!
    @IBOutlet var heroIconImageView: UIImageView!
    var agentAbilitiesVideoURL = ""
    var choosenAgentSkillName = ""
    var choosenAbilitiesImages : UIImage?
 
    override func viewDidLoad() {
        super.viewDidLoad()
        skillNameLabel.text = choosenAgentSkillName
        heroIconImageView.image = choosenAbilitiesImages
    }
    
    // 视图完全显示后再执行播放
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        playAbilitiesVideos()
    }
  
    func playAbilitiesVideos() {
        // 处理URL可选值,避免强制解包崩溃
        guard let videoURL = URL(string: agentAbilitiesVideoURL) else {
            print("无效的视频URL")
            return
        }
        let player = AVPlayer(url: videoURL)
        let controller = AVPlayerViewController()
        controller.player = player
        controller.showsPlaybackControls = true
        player.isClosedCaptionDisplayEnabled = false
        
        // 仅保留模态展示逻辑
        present(controller, animated: true) {
            player.play()
        }
    }
}

方案二:将播放器嵌入当前页面(作为子视图)

如果需要把视频播放器嵌入到当前页面的指定位置,移除模态present操作,正确处理子控制器的生命周期:

class AbilitiesDetailsViewController: UIViewController, AVPlayerViewControllerDelegate {

    @IBOutlet var skillDetailsLabel: UILabel!
    @IBOutlet var skillNameLabel: UILabel!
    @IBOutlet var heroIconImageView: UIImageView!
    var agentAbilitiesVideoURL = ""
    var choosenAgentSkillName = ""
    var choosenAbilitiesImages : UIImage?
 
    override func viewDidLoad() {
        super.viewDidLoad()
        skillNameLabel.text = choosenAgentSkillName
        heroIconImageView.image = choosenAbilitiesImages
        
        playAbilitiesVideos()
    }
  
    func playAbilitiesVideos() {
        guard let videoURL = URL(string: agentAbilitiesVideoURL) else {
            print("无效的视频URL")
            return
        }
        let player = AVPlayer(url: videoURL)
        let controller = AVPlayerViewController()
        controller.player = player
        controller.showsPlaybackControls = true
        player.isClosedCaptionDisplayEnabled = false
        
        // 正确添加子控制器流程
        addChild(controller)
        view.addSubview(controller.view)
        controller.view.frame = CGRect(x: 50 , y: 50, width: 300, height: 300)
        // 必须调用didMove,完成子控制器生命周期绑定
        controller.didMove(toParent: self)
        
        player.play()
    }
}

内容的提问来源于stack exchange,提问作者7mach

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 11:01:33