Dismissing Both Uinavigation Views and Modal Views at Once Programmatically

Dismissing both UINavigation views and Modal views at once programmatically

If you want, in iOS 6.0 (and later) projects you can use an unwind segue. For example, you can:

  1. In your top level view controller (the one you want to unwind to, not the controller you're going to unwind from), write an unwind segue method, in this case called unwindToTopLevel (personally, I find it useful if the segue bears some indication as to what the destination of the segue is, for reasons that will become apparent when we get to step 3, below):

    - (IBAction)unwindToTopLevel:(UIStoryboardSegue *)segue
    {
    NSLog(@"%s", __FUNCTION__);
    }
  2. In the Interface Builder scene from which you will initiate the unwind, control ⌘-drag from the view controller icon to the exit icon to create the unwind segue:

    Sample Image

    Generally you'd define the segue from a button to the exit outlet (and you're done), but if you want to invoke the segue programmatically, you might want to create it between the controller and the unwind outlet, like shown above.

  3. You'll get a little pop up that includes the name of your unwind segues (from the presenting controllers ... it's like magic):

    Sample Image

  4. If you're going to invoke that segue programmatically, you have to select that unwind segue in the document outline on the left side of the IB window and once you've done that, you can give the unwind segue a storyboard id:

    Sample Image

    I generally use the name of the the unwind segue for the storyboard id, but you can use whatever you want.

  5. Now, having done that, your alert view can invoke the segue:

    - (IBAction)didTouchUpInsideButton:(id)sender
    {
    [[[UIAlertView alloc] initWithTitle:nil message:@"go home" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil] show];
    }

    #pragma mark - UIAlertViewDelegate

    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    {
    if (buttonIndex != [alertView cancelButtonIndex])
    {
    [self performSegueWithIdentifier:@"unwindToTopLevel" sender:self];
    }
    }

Dismissing both UINavigation views and Modal views at once programmatically

If you want, in iOS 6.0 (and later) projects you can use an unwind segue. For example, you can:

  1. In your top level view controller (the one you want to unwind to, not the controller you're going to unwind from), write an unwind segue method, in this case called unwindToTopLevel (personally, I find it useful if the segue bears some indication as to what the destination of the segue is, for reasons that will become apparent when we get to step 3, below):

    - (IBAction)unwindToTopLevel:(UIStoryboardSegue *)segue
    {
    NSLog(@"%s", __FUNCTION__);
    }
  2. In the Interface Builder scene from which you will initiate the unwind, control ⌘-drag from the view controller icon to the exit icon to create the unwind segue:

    Sample Image

    Generally you'd define the segue from a button to the exit outlet (and you're done), but if you want to invoke the segue programmatically, you might want to create it between the controller and the unwind outlet, like shown above.

  3. You'll get a little pop up that includes the name of your unwind segues (from the presenting controllers ... it's like magic):

    Sample Image

  4. If you're going to invoke that segue programmatically, you have to select that unwind segue in the document outline on the left side of the IB window and once you've done that, you can give the unwind segue a storyboard id:

    Sample Image

    I generally use the name of the the unwind segue for the storyboard id, but you can use whatever you want.

  5. Now, having done that, your alert view can invoke the segue:

    - (IBAction)didTouchUpInsideButton:(id)sender
    {
    [[[UIAlertView alloc] initWithTitle:nil message:@"go home" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil] show];
    }

    #pragma mark - UIAlertViewDelegate

    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    {
    if (buttonIndex != [alertView cancelButtonIndex])
    {
    [self performSegueWithIdentifier:@"unwindToTopLevel" sender:self];
    }
    }

Dismissing multiple modal views

I don't think that your way is wrong. It is what Apple documentation recommends:

If you present several modal view controllers in succession, and thus build a stack of modal 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.

How to correctly dismiss a UINavigationController that's presented as a modal?

Your controller hierarchy looks like this:

UITabViewController
|
| presents
|
UINavigationController
|
| contains view controllers
|
[root, MessagesViewController]

Now, if you are inside MessagesViewController, then its navigationController is the one that is being presented and that's the one you should be dismissing but calling dismiss on MessagesViewController should work too.

However, the problem is that dismissing the navigation controller won't remove its view controllers. It seems you are holding to your navigation controller (since you are presenting it using self.navController) so the state will become

UITabViewController
|
| self.navController holds a reference to
|
UINavigationController
|
| contains view controllers
|
[root, MessagesViewController]

To properly destroy MessagesViewController you will have to either let go of the navController or you will have to pop to root (thus removing MessagesViewController from view hierarchy).

The typical solution would be not to save a reference to navController at all. You could always create a new UINavigationController when presenting.
Another solution is using a delegate - instead of dismissing from inside MessagesViewController, let it call back to the presenter, which would call

self.navController.dismiss(animated: true) {
self.navController = nil
}

Displaying modal views programmatically

You can try below code

I assume that you are using storyboard.

UIStoryboard *board = [UIStoryboard storyboardWithName:@"name" bundle:nil];
viewController *controller = [board instantiateViewControllerWithIdentifier:@"Identifier"]; // Identifier is define in storyboard
[self presentViewController:controller animated:YES completion:nil];

Please check out this link if you are still facing the problem.

Hope this helps you.

single function to dismiss all open view controllers

You can call :

self.view.window!.rootViewController?.dismiss(animated: false, completion: nil)

Should dismiss all view controllers above the root view controller.



Related Topics



Leave a reply



Submit