Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Consequences of Bad Programming: dismissViewController vs popViewController

I understand the difference between dismissViewControllerAnimated:completion: and popViewControllerAnimated:, as described on Stack Overflow and here:

-dismissViewControllerAnimated:completion: method is used to dismiss an UIViewController, which was presented by the method: -presentViewController:animated:completion:.

-popViewControllerAnimated: method of UINavigationController is used to pop a controller shown by -pushViewController:animated method of UINavigationController.

I recently caught a mistake in my app, where I was using [self dismissViewControllerAnimated:completion:] to dismiss a VC that was presented with a push in a navigation embedded app. I french fried when I should have pizza'd. I didn't catch the mistake because everything worked fine and my VC was deallocated as expected.

My question: What are the consequences of mixing these two methods up?

like image 510
Emin Israfil iOS Avatar asked Oct 29 '13 20:10

Emin Israfil iOS


2 Answers

-presentViewController:animated:completion: and -pushViewController:animated: mean different things. The former says "present this other view controller so as to replace yourself". The latter says "show this other view controller within yourself, as part of the list you're controlling".

So it's about who is considered to be in charge of the display after the transition. In the former case the navigation controller surrenders control. In the latter it retains control.

The former functionality is provided by UIViewController. The latter is specific to UINavigationController.

Because the two actions are quite different, the opposite actions are separate. Navigation controllers could catch dismissViewController:... and check how the named controller was presented, branching either into the superclass or into pop... but the conflation of tasks would be unappealing from a design and a maintenance point of view.

Since the navigation controller doesn't promise to map the one thing to the other, and UIViewController doesn't promise any particular behaviour if the controller you pass hasn't previously been presented, I think the literal answer to your question is: the consequence of mixing these two things up is undefined behaviour.

like image 117
Tommy Avatar answered Oct 13 '22 19:10

Tommy


Im not sure if I can explain this the best I would like to but let me try.

I am working on a Tab Based app right now, and each tab has its own navigation controller. For side features, I have a barbuttonitem on the navbar branch out to a modal view (and in some cases a modal to a brand new navigation controller to control the backstack for the particular feature's path.

I will call dismissViewController on the root view of any navigation controller that I launch off of another as a modal. (I hope that makes sense.)

Maybe this is better:

The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, it automatically forwards the message to the presenting view controller.

If you present several view controllers in succession, thus building a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.

Push for navigation based view controllers, and use popViewController when needed. Modally introduce anything that branches off from the navigation, and use dismissViewController as needed in that case.

like image 35
William Riley Avatar answered Oct 13 '22 18:10

William Riley