UINavigationController类型转换失败与返回按钮失效问题求助
你这两个问题都是iOS容器控制器嵌套时的常见坑,我帮你一步步拆解解决方案:
问题1:菜单按钮点击崩溃(类型转换失败)
为啥会崩?
你的VoiceViewController是被包在UINavigationController里的,而这个导航控制器才是VoiceParentViewController的子容器。所以你在VoiceViewController里拿self.parent,得到的是那个导航控制器,不是VoiceParentViewController,强行转类型肯定会崩啊!
怎么修?
有两种简单的办法:
办法1:直接通过导航控制器找父VC
修改VoiceViewController里的菜单点击方法:
@IBAction func action_menu(_ sender: Any) { // 先拿当前VC的导航控制器,再取它的父级(就是我们要的VoiceParentViewController) guard let navController = navigationController, let parentVC = navController.parent as? VoiceParentViewController else { return } parentVC.menuTouched() }
办法2:写个通用工具方法(推荐,以后复用方便)
给UIViewController加个扩展,专门用来找指定类型的父控制器:
extension UIViewController { func findParent<T: UIViewController>(ofType targetType: T.Type) -> T? { var currentParent = parent while currentParent != nil { if let match = currentParent as? T { return match } currentParent = currentParent?.parent } return nil } }
然后在菜单点击里这么用:
@IBAction func action_menu(_ sender: Any) { if let parentVC = findParent(ofType: VoiceParentViewController.self) { parentVC.menuTouched() } }
问题2:直接嵌入VoiceParentViewController后导航控制器为nil
原因很简单
当你直接把VoiceParentViewController塞进父容器时,它自己根本不在任何UINavigationController的栈里,所以它的navigationController是nil,里面的NewConversationViewController自然也拿不到导航控制器,popToRootViewController当然没用。
修复方案
首选方案:保留原嵌套结构,只修复问题1就行
你最开始的结构(VoiceVC → UINavigationController → VoiceParentViewController → 父VC)其实是合理的,只要把问题1修好,导航功能完全正常——因为VoiceViewController的导航控制器是存在的,NewConversationViewController是push进去的,它能正常拿到导航控制器,popToRootViewController也能正常工作。
如果你非要直接嵌入VoiceParentViewController
那得给它内部的VoiceVC套个导航控制器,比如在VoiceParentViewController的viewDidLoad里加这段:
override func viewDidLoad() { super.viewDidLoad() // 找到容器里的VoiceViewController if let voiceVC = children.first(where: { $0 is VoiceViewController }) { // 给它套个导航控制器 let navController = UINavigationController(rootViewController: voiceVC) // 替换容器里的VC为导航控制器 voiceVC.removeFromParent() navController.view.frame = container_voiceVC.bounds container_voiceVC.addSubview(navController.view) addChild(navController) navController.didMove(toParent: self) } }
不过这种方式比较麻烦,还是推荐用第一种方案,省事儿还不容易出错。
内容的提问来源于stack exchange,提问作者Mohamed Lee

