I am creating two child view controllers childA
and childB
to be displayed and managed by a view controller parent
. I'm hoping to master how nested child controllers work, but right now end up with a crash.
I created a generic extension to UIViewController to help me add a child controller:
@nonobjc public extension UIViewController {
func addChildController(_ child: UIViewController, frame: CGRect? = nil) {
addChild(child)
if let frame = frame {
child.view.frame = frame
}
view.addSubview(child.view)
child.didMove(toParent: self)
}
}
I start with a parent controller that adds a child controller, which is revealed when I hit the "preview" button:
class ParentViewController: UIViewController {
lazy var childA = ChildAViewController(nibName: "ChildAViewController", bundle: nil)
override func viewDidLoad() {
super.viewDidLoad()
addChildController(childA, frame: view.bounds)
}
@IBAction func preview(_ sender: Any) {
childA.view.isHidden = false
}
}
This childA
controller in turn adds its own child controller childB
. There are buttons on each of these controllers' views to flip back and forth between them.
class ChildAViewController: UIViewController {
lazy var childB = ChildBViewController(nibName: "ChildBViewController", bundle: nil)
override func viewDidLoad() {
super.viewDidLoad()
view.isHidden = true
addChildController(childB, frame: view.bounds)
childB.childA = self
}
@IBAction func showChildBView(_ sender: Any) {
childB.view.isHidden = false
let transitionOptions: UIView.AnimationOptions = [.transitionFlipFromRight]
UIView.transition(from: view, to: childB.view, duration: 1, options: transitionOptions) { success in
self.view.isHidden = true
}
}
}
class ChildBViewController: UIViewController {
var childA: ChildAViewController?
override func viewDidLoad() {
super.viewDidLoad()
view.isHidden = true
}
@IBAction func showChildAView(_ sender: Any) {
childA!.view.isHidden = false
let transitionOptions: UIView.AnimationOptions = [.transitionFlipFromRight]
UIView.transition(from: view, to: childA!.view, duration: 1, options: transitionOptions) { success in
self.view.isHidden = true
}
}
}
What's strange is that I can flip back and forth, displaying A then B then A, but then when it's about to display B again, the app suddenly it crashes with this error:
2019-11-20 16:09:19.984575-0800 MyApp[95630:6863114] *** Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency', reason: 'child view controller:<MyApp.ChildBController: 0x7fb05a03b200> should have parent view controller:<MyApp.ParentController: 0x7fb05945bf10> but actual parent is:<MyApp.ChildAController: 0x7fb05a074e00>'
What's going on here? I don't have this issue if I create both childA
and childB
as children of my parent
, not a child and a 'grandchild'. But I want the ability to nest child view controllers as stated in the documentation, and in fact actually want to nest more deeply.