a bug about [UINavigationController setViewControllers: animated:]

I find a bug about [UINavigationController setViewController: animated:]. and i get crash every time in iOS 9.0+. I don't try iOS 9.0-.


In my case, i have a rootViewController which has 2 childViewControllers: UINavigationControllerA, UINavigationControllerB


UINavigationControllerA has 1 childViewController, like this: UINavigationControllerA.viewControllers == [UIViewControllerA]


UINavigationControllerB also has 1 childViewController, like this: UINavigationControllerB.viewControllers == [UIViewControllerB]


then UINavigationControllerB push UIViewControllerC, so UINavigationControllerB.viewControllers == [UIViewControllerB, UIViewControllerC]


at last, put UIViewControllerC to UINavigationControllerA


[UINavigationControllerB setViewControllers:@[UIViewControllerB] animated:NO]

[UINavigationControllerA setViewControllers:@[UIViewControllerA, UIViewControllerC] animated:NO]


it will crash!


crash log:


Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency', reason: 'child view controller:<UIViewControllerC: 0x7f7fd17453a0> should have parent view controller:<UINavigationController: 0x7f7fd2817400> but requested parent is:<UINavigationController: 0x7f7fd182f800>'


here is demo.https://github.com/l1002k/NaviSetViewControllersBugDemo


if i do [UIViewControllerC.view removeFromSuperview] before setViewControllers. it will OK, i guess the UIViewController.parentViewController reply on the UIViewController.view.superview.

I suggest filing a bugreport.

AFAIK the problem is that UIViewControllerC first is a child of UINavigationControllerB.

And calling

[UINavigationControllerB setViewControllers:@[UIViewControllerB] animated:NO]

does not immediately remove UIViewControllerC because it works async somehow. (I've in mind I did stumble accross this issue a few years ago)

So, when calling

[UINavigationControllerA setViewControllers:@[UIViewControllerA, UIViewControllerC] animated:NO]

UINavigationControllerA may assume that UIViewControllerC does not have a parent, while it stil has one.


Maybe it's different when you call

UINavigationControllerB.viewControllers = @[UIViewControllerB];


Dirk

-setViewControllers will call -setViewControllers:animated:NO


it will carch too...

I just ran into the issue, replying with my fix in case this can help anyone else out.


If you call layoutIfNeeded() on the navigation controller you removed the view controller from the crash won't happen.

[UINavigationControllerB setViewControllers:@[UIViewControllerB] animated:NO]
[UINavigationControllerB.view layoutIfNeeded]

[UINavigationControllerA setViewControllers:@[UIViewControllerA, UIViewControllerC] animated:NO]

I get the same issue with iOS 9.0. i have to use removeFromSuperview to avoid the crash before setViewControllers. it looks strange

a bug about [UINavigationController setViewControllers: animated:]
 
 
Q