Swift子视图控制器需共用父控制器报错问题排查
问题原因与解决方法
这个报错的核心是:调用transitionFromViewController:toViewController:时,两个子控制器必须已经是同一个父控制器的子节点。如果其中一个控制器还没被添加为当前容器控制器的子控制器,就会触发这个错误。
正确实现流程
不管是首次加载子控制器,还是在两个子控制器间切换,都要严格遵循以下步骤:
- 确保要切换到的目标控制器已被添加为当前容器控制器的子控制器(未添加则先执行添加操作)
- 调用过渡方法完成视图切换,或首次添加时直接将子控制器的view挂载到容器视图
修正后的代码示例
假设你的容器控制器为ContainerViewController,包含loadingVC和内容控制器两个子节点:
class ContainerViewController: UIViewController { private let loadingVC = LoadingViewController() private var contentVC: UIViewController? // 容器视图,用于承载子控制器的view private let containerView = UIView() override func viewDidLoad() { super.viewDidLoad() setupContainerView() // 首次加载显示loading控制器 addChild(loadingVC) loadingVC.view.frame = containerView.bounds containerView.addSubview(loadingVC.view) loadingVC.didMove(toParent: self) } private func setupContainerView() { containerView.frame = view.bounds containerView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(containerView) } // 切换到内容控制器的方法 func switchToContent(_ targetVC: UIViewController) { if let existingContent = contentVC { // 已有内容控制器,直接执行过渡切换 transitionFrom(loadingVC, to: existingContent, duration: 0.3, options: .transitionCrossDissolve) { [weak self] _ in self?.loadingVC.removeFromParent() } } else { // 首次添加内容控制器,先完成子控制器绑定 addChild(targetVC) targetVC.view.frame = containerView.bounds // 执行过渡动画 transitionFrom(loadingVC, to: targetVC, duration: 0.3, options: .transitionCrossDissolve) { [weak self] finished in guard finished else { return } self?.loadingVC.removeFromParent() targetVC.didMove(toParent: self) self?.contentVC = targetVC } } } }
关键注意事项
- 添加子控制器时,必须先调用
addChild(_:),再将其view添加到容器视图,最后调用didMove(toParent:)完成生命周期绑定 - 移除子控制器时,
transitionFrom...方法会自动处理willMove(toParent: nil),只需在completion回调里调用removeFromParent()即可 - 调用过渡方法前,务必确认两个子控制器都已属于当前容器控制器的子节点
内容的提问来源于stack exchange,提问作者user23454452
相关产品推荐
相关产品推荐

