iOS应用崩溃:尝试模态展示已有父控制器的AVPlayerViewController
问题分析与解决方案
崩溃原因
你遇到的崩溃核心原因有两个:
- 重复控制器生命周期操作:在
playAbilitiesVideos中同时对AVPlayerViewController执行了present(模态展示)和addChild+view.addSubview(作为子控制器嵌入)操作——同一个视图控制器不能同时被模态展示和添加为子控制器,这会导致系统判定其存在冲突的父控制器关系,触发崩溃。 - 过早执行模态操作:在
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
相关产品推荐
相关产品推荐

