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

IphoneIosViewControllerModal Dialog

Iphone Problem Overview


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

Iphone Solutions


Solution 1 - Iphone

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 - Iphone

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 - Iphone

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 - Iphone

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 - Iphone

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

Solution 6 - Iphone

This should work.

if(self.parentViewController.modalViewController == self)…

Solution 7 - Iphone

Best way to check

 if (self.navigationController.presentingViewController) {
         NSLog(@"Model Present");
    }

Solution 8 - Iphone

If you don't need to distinguish between full-screen modal views and non-modal views, which is the case in my project (I was dealing with a problem that only occurs with form sheets and page sheets), you can use the modalPresentationStyle property of UIViewController:

switch (self.modalPresentationStyle) {
	case 0: NSLog(@"full screen, or not modal"); break;
	case 1: NSLog(@"page sheet"); break;
	case 2: NSLog(@"form sheet"); break;
}

Solution 9 - Iphone

In Swift:

func isUIViewControllerPresentedAsModal() -> Bool {
    if((self.presentingViewController) != nil) {
        return true
    }

    if(self.presentingViewController?.presentedViewController == self) {
        return true
    }

    if(self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) {
        return true
    }

    if((self.tabBarController?.presentingViewController?.isKindOfClass(UITabBarController)) != nil) {
        return true
    }

    return false
}

Solution 10 - Iphone

In my project I have a view controller (Detail) that can be presented either modally (when adding a new item) or with push (when editing an existing one) by Master view controller. When user taps [Done] the Detail view controller calls Master view controller's method to notify that it is ready to be closed. Master has to determine how Detail is presented in order to know how to close it. This is how I do this:

UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
    [self dismissViewControllerAnimated:YES completion:NULL];
} else {
    [self.navigationController popViewControllerAnimated:YES];
}

Solution 11 - Iphone

A hack like this might work.

UIViewController* child = self;
UIViewController* parent = child.parentViewController;
while (parent && parent.modalViewController != child) {
    child = parent;
    parent = child.parentViewController;
}
if (parent) {
    // A view controller in the hierarchy was presented as a modal view controller
}

However, I think my previous answer is a cleaner solution.

Solution 12 - Iphone

What worked for me is following:

// this is the trick: set parent view controller as application's window root view controller
UIApplication.sharedApplication.delegate.window.rootViewController = viewController;

// assert no modal view is presented
XCTAssertNil(viewController.presentedViewController);

// simulate button tap which shows modal view controller
[viewController.deleteButton sendActionsForControlEvents:UIControlEventTouchUpInside];

// assert that modal view controller is presented
XCTAssertEqualObjects(viewController.presentedViewController.class, MyModalViewController.class);

As far as I tested it, this works for iOS7 and iOS8. Didn't try on iOS6 however.

Solution 13 - Iphone

I've looked a bit around to find the right answer to this question, and I couldn't find any which covered all the possible scenarios. I wrote these few lines of code which seem to do the job. You can find few inline comments to figure out what's been checked.

- (BOOL)isModal {
    BOOL modal = NO;
    if ([self presentingViewController]) { //Some view Controller is presenting the current stack
        UIViewController *presented = [[self presentingViewController] presentedViewController]; // What's been presented
        if ([presented respondsToSelector:@selector(viewControllers)]) { // There's a stack
            NSArray *viewControllers = [presented performSelector:@selector(viewControllers)];
            modal = [viewControllers firstObject] == self; // Current VC is presented modally if it's the first in the stack
        }
        else {
            modal = presented == self; // Don't think this is actually needed. set modal = YES should do the job tho.
        }
    }
    return modal;
}

Hope this help.

Solution 14 - Iphone

Here's my modified version of @GabrielePetronella's isModal, which works with contained view controllers in that it walks up the parentViewController hierarchy first. Also pulled the code out into multiple lines so it's clear what it's doing.

var isModal: Bool {
    // If we are a child view controller, we need to check our parent's presentation
    // rather than our own.  So walk up the chain until we don't see any parentViewControllers
    var potentiallyPresentedViewController : UIViewController = self
    while (potentiallyPresentedViewController.parentViewController != nil) {
        potentiallyPresentedViewController = potentiallyPresentedViewController.parentViewController!
    }

    if self.presentingViewController?.presentedViewController == potentiallyPresentedViewController {
        return true
    }

    if let navigationController = potentiallyPresentedViewController.navigationController {
        if navigationController.presentingViewController?.presentedViewController == navigationController {
            return true
        }
    }

    return potentiallyPresentedViewController.tabBarController?.presentingViewController is UITabBarController
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionlukewarView Question on Stackoverflow
Solution 1 - IphoneGabriele PetronellaView Answer on Stackoverflow
Solution 2 - IphoneFelipe SabinoView Answer on Stackoverflow
Solution 3 - IphoneRajView Answer on Stackoverflow
Solution 4 - IphonehpiqueView Answer on Stackoverflow
Solution 5 - IphoneSemih CihanView Answer on Stackoverflow
Solution 6 - IphonekubiView Answer on Stackoverflow
Solution 7 - IphoneSunny ShahView Answer on Stackoverflow
Solution 8 - IphonearlomediaView Answer on Stackoverflow
Solution 9 - IphoneKing-WizardView Answer on Stackoverflow
Solution 10 - IphoneOlexView Answer on Stackoverflow
Solution 11 - IphonehpiqueView Answer on Stackoverflow
Solution 12 - Iphonemixtly87View Answer on Stackoverflow
Solution 13 - IphoneDennyLouView Answer on Stackoverflow
Solution 14 - IphoneRyanView Answer on Stackoverflow