I have an iOS app that has a connection to a server. If we get disconnected, I want to be able to dismiss the top view controllers to get back to a "connecting to server" view controller. The problem is that a disconnection can occur at any time, including during a transition between view controllers.
The view controller hierarchy is like so:
ConnectingToServerViewController
SignInViewController
MainAppViewController
- Other view controllers
When a disconnection is detected I want the view hierarchy to collapse back to:
ConnectingToServerViewController
So when a disconnection is detected, this method is called on the ConnectingToServerViewController
to dismiss anything that it has presented and go back to attempting to connect to server:
- (void)restartSession
{
if (self.presentedViewController) {
[self dismissViewControllerAnimated:NO completion:nil];
}
}
However, if I try to dismiss while a view transition is occurring, I get errors such as
*** Assertion failure in -[UIWindowController transition:fromViewController:toViewController:target:didEndSelector:], /SourceCache/UIKit/UIKit-2380.17/UIWindowController.m:211
attempt to dismiss modal view controller whose view does not currently appear. self = <YYYYYViewController: 0x2089c8a0> modalViewController = <XXXXXViewController: 0x208e6610>
attempt to dismiss modal view controller whose view does not currently appear. self = <WWWWWWViewController: 0x1fd9e990> modalViewController = <YYYYYViewController: 0x2089c8a0>
The first of which will crash the app, the second will just not dismiss anything and continue to show the current presented view controller.
Thoughts:
- delays won't work since we don't know when to start the delay
- is there a way to track when view transitions complete?
- should all view controllers override willAppear, didAppear and alert the app when it is safe to dismiss?
- perhaps instead of dismiss, I should just set a new root view controller?
- I've made sure that all overridden view(will|did)(dis)?appear methods call the appropriate super method.
- Any solution that requires all view controllers to override view(did|will)appear methods to track state sounds like it could cause issues if we forget to set the base class for a new view controller.