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

61,292

Solution 1

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.

Solution 2

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

Solution 3

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

Solution 4

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.

Solution 5

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
Share:
61,292
lukewar
Author by

lukewar

Updated on September 17, 2020

Comments

  • lukewar
    lukewar over 3 years

    Is it possible to check inside ViewController class that it is presented as modal view controller?

  • lukewar
    lukewar almost 14 years
    Unfortunately this does not work. It was my first try. But returned modalViewController ins nil :(.
  • lukewar
    lukewar almost 14 years
    RIght and this is what i have did but I was looking for some other neat solution. Thanks.
  • Ajay Choudhary
    Ajay Choudhary almost 14 years
    If you just get 'self.parentViewController' does it return the correct parent object?
  • hpique
    hpique almost 14 years
    The problem might be that your UIViewController subclass is inside a UINavigationController or a UITabBarController (or both), in which case you might need to dig a bit more in the view hierarchy to find out the parent that was presented as a modal view controller.
  • Felipe Sabino
    Felipe Sabino over 12 years
    @hgpc I needed this chck in my project, so I just added an answer to check for both UINavigationController and UITabBarController cases. It is working pretty well so far
  • Felipe Sabino
    Felipe Sabino over 12 years
    this solution does not work if you are presenting a UINavigationController as modal... unless you create a custom navigation controller just to add this property. And after that, inside the controllers, you will have to keep casting self.navigationController to this custom class every time you need to check if the controller is presented as modal
  • mashdup
    mashdup about 11 years
    Works perfectly, use if (self.presentingViewController) {//This is a modal viewContoller} else {//This is a normal ViewController}
  • Bart Jacobs
    Bart Jacobs almost 11 years
    Keep in mind that the modalViewController property is deprecated as of iOS 6. The documentation suggests to use presentedViewController instead.
  • Felipe Sabino
    Felipe Sabino almost 11 years
    @BartJacobs good point! I havent't looked at this answer after iOS6 release, so it might be not up-to-date. I will try to make some tests later in the week to update it, tks!
  • Daniel Rinser
    Daniel Rinser over 10 years
    IMHO, this is the only correct answer here. Just check for the presence of a presentingViewController. It will also work in container view controllers, as it automatically traverses the ancestors.
  • Roman
    Roman about 10 years
    NSLog(@"%@", self.navigationController.parentViewController) prints (null) - could you please explain why? My ViewController is connected with modal view controller through navController in storyboard.
  • Felipe Sabino
    Felipe Sabino about 10 years
    @oyatek can you use pastebin or something similar and show some code?
  • Roman
    Roman about 10 years
    @Feilpe I found the problem - .parentViewController is deprecated, .presentingViewController must be used instead.
  • Felipe Sabino
    Felipe Sabino about 10 years
    @oyatek I don't get it... thats exactly why I added the iOS 5+ fallback with the presentingViewController logic... Isn't it working in some specific case you have?
  • Felipe Sabino
    Felipe Sabino about 10 years
    @oyatek I tested my code in the new ios and now I got what you meant, I edited my answer with the deprecation notice and you should look at Gabriele Petronella's answer - stackoverflow.com/a/16764496/429521 - for the correct code. Thanks :)
  • Felipe Sabino
    Felipe Sabino about 10 years
    good catch, I just had to use it again after a long time and noticed that the deprecation happened... I edited my answer so that people start looking here for the correct code when using iOS 6+, thanks
  • meaning-matters
    meaning-matters almost 10 years
    Does not work if parent view controller is a modal on which our view controller is pushed.
  • CocoaBob
    CocoaBob about 9 years
    There's a bug, we should check if both sides are nil, because nil == nil returns YES, and it's not the result we want.
  • Gabriele Petronella
    Gabriele Petronella about 9 years
    @CocoaBob, thanks, that was indeed a corner case I did not consider. I've updated the answer to check for nil in the second case.
  • Michael Waterfall
    Michael Waterfall about 9 years
    @GabrielePetronella Do you mind if I update the answer to also include a Swift implementation of the method?
  • Gabriele Petronella
    Gabriele Petronella about 9 years
    @MichaelWaterfall that'd be greatly appreciated, thanks
  • mariusLAN
    mariusLAN over 8 years
    There is a Problem with this use case. If I'm in a root view controller of a UINavigationController it still returns true without any modal presentation.
  • Ryan
    Ryan about 8 years
    Also note that self.presentingViewController?.presentedViewController == self doesn't work if this code is run in a contained view controller. I think in that case the check needs to be something like self.presentingViewController?.presentedViewController == parentViewController.
  • isoiphone
    isoiphone almost 8 years
    The first if statement covers everything that is in the second if statement, rendering the second statement redundant. I'm not sure what the intention is here.