78

Can anyone give me the example code that I can use to first present a modal view controller, then dismiss it? This is what I have been trying:

NSLog(@"%@", blue.modalViewController);
[blue presentModalViewController:red animated:YES];
NSLog(@"%@", blue.modalViewController);
[blue dismissModalViewControllerAnimated:YES];
NSLog(@"%@", blue.modalViewController);

This code is in viewDidLoad ("blue" and "red" are both subclasses of UIViewController). I expect that I will show the red view and then immediately hide it, with some animation. However this piece of code only presents the modal view and does not dismiss it. Any idea? The first log shows "null" while the two other logs show <RedViewController: 0x3d21bf0>

Another point is, if I put this code in applicationDidFinishLaunching: the red view does not appear at all, and all logs get "null"

pkamb
  • 26,648
  • 20
  • 124
  • 157
phunehehe
  • 8,078
  • 7
  • 43
  • 77
  • As someone says below, `presentModalViewController:animated:` is deprecated. Now you need to use `presentModalViewController:animated:completion:` and execute the following operations in the completion block (if you want to wait until `red` is presented). Anyway, read the article that @MatterGoal suggests: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html%23//apple_ref/doc/uid/TP40007457-CH111-SW1. – Ferran Maylinch Apr 06 '15 at 22:54

6 Answers6

109

First of all, when you put that code in applicationDidFinishLaunching, it might be the case that controllers instantiated from Interface Builder are not yet linked to your application (so "red" and "blue" are still nil).

But to answer your initial question, what you're doing wrong is that you're calling dismissModalViewControllerAnimated: on the wrong controller! It should be like this:

[blue presentModalViewController:red animated:YES];
[red dismissModalViewControllerAnimated:YES];

Usually the "red" controller should decide to dismiss himself at some point (maybe when a "cancel" button is clicked). Then the "red" controller could call the method on self:

[self dismissModalViewControllerAnimated:YES];

If it still doesn't work, it might have something to do with the fact that the controller is presented in an animation fashion, so you might not be allowed to dismiss the controller so soon after presenting it.

Tom van Zummeren
  • 8,729
  • 12
  • 48
  • 59
  • 58
    According to the View Controller Programming guide for iPhone OS, this is incorrect when it comes to dismissing modal view controllers you should use delegation. So before presenting your modal view make yourself the delegate and then call the delegate from the modal view controller to dismiss. – Oscar Gomez Jan 14 '10 at 15:03
  • 1
    Remember that since io6 this way of presenting the modal view is depreciated. Use: [self presentViewController: animated: completion:]; instead – simon_smiley Jul 14 '14 at 04:27
  • 5
    @OscarGomez No, the View Controller Programming Guide **does not** say this approach is incorrect.  It does say that the approach you suggest is the “preferred approach”.  In other words, while your approach may work for many situations, it is by-design not the only approach, just the one you should try first.  _I suggest you add the approach you're citing as an additional answer, since there are multiple viable answers to a question like this and yours may be better for some readers._ – Slipp D. Thompson Jul 31 '14 at 07:22
  • 4
    `[self dismissModalViewControllerAnimated:YES];` is deprecated – alternatiph Sep 08 '14 at 23:17
  • What's the difference between calling `dismissModalViewControllerAnimated` on `red` or `blue`? From the docs it seems that we should call it on `blue` (the presenting VC)... – Ferran Maylinch Apr 06 '15 at 22:51
19

Swift

Updated for Swift 3

enter image description here

Storyboard

Create two View Controllers with a button on each. For the second view controller, set the class name to SecondViewController and the storyboard ID to secondVC.

Code

ViewController.swift

import UIKit
class ViewController: UIViewController {

    @IBAction func presentButtonTapped(_ sender: UIButton) {
        
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let myModalViewController = storyboard.instantiateViewController(withIdentifier: "secondVC")
        myModalViewController.modalPresentationStyle = UIModalPresentationStyle.fullScreen
        myModalViewController.modalTransitionStyle = UIModalTransitionStyle.coverVertical
        self.present(myModalViewController, animated: true, completion: nil)
    }
}

SecondViewController.swift

import UIKit
class SecondViewController: UIViewController {
    
    @IBAction func dismissButtonTapped(_ sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }
}

Source:

Community
  • 1
  • 1
Suragch
  • 364,799
  • 232
  • 1,155
  • 1,198
13

The easiest way i tired in xcode 4.52 was to create an additional view and connect them by using segue modal(control drag the button from view one to the second view, chose Modal). Then drag in a button to second view or the modal view that you created. Control and drag this button to the header file and use action connection. This will create an IBaction in your controller.m file. Find your button action type in the code.

[self dismissViewControllerAnimated:YES completion:nil];
max
  • 381
  • 6
  • 15
  • Note that this automatically forwards the message to `self.presentingViewController` (according to the UIViewController documentation) so for clarity it's better to call `[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];` – Hatchmaster J Jun 22 '15 at 12:39
9

presentModalViewController:

MainViewController *mainViewController=[[MainViewController alloc]init];
[self.navigationController presentModalViewController:mainViewController animated:YES];

dismissModalViewController:

[self dismissModalViewControllerAnimated:YES];
Jerry Thomsan
  • 1,379
  • 10
  • 9
3

The easiest way to do it is using Storyboard and a Segue.

Just create a Segue from the FirstViewController (not the Navigation Controller) of your TabBarController to a LoginViewController with the login UI and name it "showLogin".

Create a method that returns a BOOL to validate if the user logged in and/or his/her session is valid... preferably on the AppDelegate. Call it isSessionValid.

On your FirstViewController.m override the method viewDidAppear as follows:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    if([self isSessionValid]==NO){
        [self performSegueWithIdentifier:@"showLogin" sender:self];
    }
}

Then if the user logged in successfully, just dismiss or pop-out the LoginViewController to show your tabs.

Works 100%!

Hope it helps!

Oscar Salguero
  • 9,765
  • 5
  • 48
  • 46
3

Swift

self.dismissViewControllerAnimated(true, completion: nil)

Michael
  • 8,464
  • 2
  • 59
  • 62