问题产生
最近,在集成一个全屏广告页的时候,遇到视图控制器的生命周期异常的问题:除了viewDidLoad,其余函数都没有执行。广告页本身是一个 AdsVC,当某个页面需要展示全屏广告的时候,将自己作为参数传递给 AdsVC。在 AdsVC 中,会把调用者作为一个 container controller,进行页面的添加。
对于普通的 view controller,这样处理没有问题。但是,当如 UINavigationController 的 VC 调用的时候,会发生 AdsVC 的生命周期异常的问题。
原因和解决
基本确定 UINavigationController 作为 iOS 原生的 container controller,对 child controller 的添加/移除有内部的实现,从而导致 appear 相关的函数没有执行。
通过查看头文件,可以发现:
Discussion
If you are implementing a custom container controller, use this method to tell the child that its views are about to appear or disappear. Do not invoke viewWillAppear(_:), viewWillDisappear(_:), viewDidAppear(_:), or viewDidDisappear(_:) directly.
func beginAppearanceTransition(_ isAppearing: Bool, animated: Bool)
于是,解决方法就是调用 AppearanceTransition 相关的函数,如下:
open func showIn(_ viewController: UIViewController){
viewController.addChild(self)
self.view.frame = viewController.view.bounds
if viewController is UINavigationController {
self.beginAppearanceTransition(true, animated: true)
viewController.view.addSubview(self.view)
self.view.alpha = 0
UIView.animate(withDuration: 0.2, animations: {
self.view.alpha = 1
}) { (_) in
self.endAppearanceTransition()
self.didMove(toParent: viewController)
}
}else {
viewController.view.addSubview(self.view)
self.didMove(toParent: viewController)
}
}
open func removeFrom(_ viewController: UIViewController){
if viewController.view.subviews.contains(self.view) {
if viewController is UINavigationController {
self.willMove(toParent: nil)
self.beginAppearanceTransition(false, animated: true)
UIView.animate(withDuration: 0.2, animations: {
self.view.alpha = 0
}) { (_) in
self.view.removeFromSuperview()
self.endAppearanceTransition()
self.removeFromParent()
}
}else {
self.view.removeFromSuperview()
self.removeFromParent()
}
}
}
Comments