addChildViewController仅适用于容器视图控制器?非容器场景使用是否合规?
关于addChildViewController的正确使用场景解析
咱先直接给你个明确答案:从苹果官方的设计意图来说,addChildViewController确实是专门为容器视图控制器设计的,也就是官方文档里说的“仅应由自定义容器视图控制器的实现调用”。
先把官方的定义和说明摆出来:
方法定义:
func addChildViewController(_ childController: UIViewController)
官方说明:此方法仅应由自定义容器视图控制器的实现调用,重写时必须调用super。
那为啥你会看到大量非容器场景下的示例呢?其实是有历史原因的:
- 在iOS 5及更早的版本里,如果你要把一个VC的view嵌入到另一个VC的view层级中,必须手动维护父子VC的关系,不然会出现生命周期混乱、内存管理出问题的情况,所以很多开发者养成了调用addChildViewController的习惯,哪怕没用到containerView。
- 到了iOS 6之后,苹果优化了VC层级的自动管理,但很多老代码或者不规范的示例还是沿用了之前的写法,甚至只调用了addChildViewController,却没处理后续的生命周期方法,这其实是不对的。
再说说你提到的“未使用containerView直接添加”的做法是否正确:
这种只调用addChildViewController,却不遵循完整父子VC生命周期流程的用法,是不规范且存在风险的:
- 你只调用了
addChildViewController(childVC),却没调用childVC.didMove(toParentViewController: self),会导致子VC的生命周期方法(比如viewWillAppear、viewDidDisappear)无法正确触发,业务逻辑很可能出问题。 - 父VC销毁时,子VC的内存可能无法正常释放,容易引发内存泄漏。
- 这种写法不符合苹果的设计规范,后续iOS版本更新可能会出现兼容性问题。
如果确实需要在一个VC里嵌入另一个VC的内容,正确的流程应该是这样的:
- 创建子VC实例:
let childVC = ChildViewController() - 调用addChildViewController建立父子关系:
addChildViewController(childVC) - 将子VC的view添加到父VC的view层级,并设置好布局(不用containerView也可以,但布局要正确):
view.addSubview(childVC.view) childVC.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ childVC.view.topAnchor.constraint(equalTo: view.topAnchor), childVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), childVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), childVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) - 通知子VC完成移动:
childVC.didMove(toParentViewController: self) - 移除子VC时也要走完整流程:
childVC.willMove(toParentViewController: nil) childVC.view.removeFromSuperview() childVC.removeFromParentViewController()
总结一下:虽然网上有很多不规范的示例,但从官方设计和最佳实践角度,addChildViewController应该要么用于自定义容器VC的实现,要么在手动管理父子VC关系时遵循完整的生命周期流程,不能随意调用哦。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

