Is it possible to determine whether ViewController is presented as Modal?

Since modalViewController has been deprecated in iOS 6, here's a version that works for iOS 5+ and that compiles without warnings.

Objective-C:

- (BOOL)isModal {
    return self.presentingViewController.presentedViewController == self
      || (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController)
      || [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
}

Swift:

var isModal: Bool {
    return self.presentingViewController?.presentedViewController == self
        || (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController)
        || self.tabBarController?.presentingViewController is UITabBarController
}

Hat tip to Felipe's answer.


If you a looking for iOS 6+, this answer is deprecated and you should check Gabriele Petronella's answer


There is no neat way to do that, as a property or method native to UIKit. What you can do is to check several aspects of your controller to ensure it is presented as modal.

So, to check if the current (represented as self in the code bellow) controller is presented in a modal way or not, I have the function bellow either in a UIViewController category, or (if your project does not need to use other UIKit controllers, as UITableViewController for example) in a base controller that my other controllers inherit of

-(BOOL)isModal {

     BOOL isModal = ((self.parentViewController && self.parentViewController.modalViewController == self) || 
            //or if I have a navigation controller, check if its parent modal view controller is self navigation controller
            ( self.navigationController && self.navigationController.parentViewController && self.navigationController.parentViewController.modalViewController == self.navigationController) || 
            //or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
            [[[self tabBarController] parentViewController] isKindOfClass:[UITabBarController class]]);

    //iOS 5+
    if (!isModal && [self respondsToSelector:@selector(presentingViewController)]) {

        isModal = ((self.presentingViewController && self.presentingViewController.modalViewController == self) || 
             //or if I have a navigation controller, check if its parent modal view controller is self navigation controller
             (self.navigationController && self.navigationController.presentingViewController && self.navigationController.presentingViewController.modalViewController == self.navigationController) || 
             //or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
             [[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]]);

    }

    return isModal;        

}

EDIT: I added the last check to see if a UITabBarController is being used, and you present another UITabBarController as modal.

EDIT 2: added iOS 5+ check, where UIViewController does not answer for parentViewController anymore, but to presentingViewController instead.

EDIT 3: I've created a gist for it just in case https://gist.github.com/3174081


In iOS5+, As you can see in UIViewController Class Reference, you can get it from property "presentingViewController".

presentingViewController The view controller that presented this view controller. (read-only)

@property(nonatomic, readonly) UIViewController *presentingViewController
Discussion

If the view controller that received this message is presented by another view controller, this property holds the view controller that is presenting it. If the view controller is not presented, but one of its ancestors is being presented, this property holds the view controller presenting the nearest ancestor. If neither the view controller nor any of its ancestors are being presented, this property holds nil.

Availability
Available in iOS 5.0 and later.
Declared In
UIViewController.h


If there isn't, you can define a property for this (presentedAsModal) in your UIViewController subclass and set it to YES before presenting the ViewController as a modal view.

childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];

You can check this value in your viewWillAppear override.

I believe there isn't an official property that states how the view is presented, but nothing prevents you from creating your own.


Petronella's answer does not work if self.navigationController is modally presented but self is not equal to self.navigationController.viewControllers[0], in that case self is pushed.

Here is how you could fix the problem.

return self.presentingViewController.presentedViewController == self
            || (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController && self == self.navigationController.viewControllers[0])
            || [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];

And in Swift:

return self.presentingViewController?.presentedViewController == self
        || (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController && self.navigationController?.viewControllers[0] == self)
        || self.tabBarController?.presentingViewController is UITabBarController