Is it possible to determine whether ViewController is presented as Modal?
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
lukewar
Updated on September 17, 2020Comments
-
lukewar over 3 years
Is it possible to check inside ViewController class that it is presented as modal view controller?
-
lukewar almost 14 yearsUnfortunately this does not work. It was my first try. But returned modalViewController ins nil :(.
-
lukewar almost 14 yearsRIght and this is what i have did but I was looking for some other neat solution. Thanks.
-
Ajay Choudhary almost 14 yearsIf you just get 'self.parentViewController' does it return the correct parent object?
-
hpique almost 14 yearsThe 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 over 12 years@hgpc I needed this chck in my project, so I just added an answer to check for both
UINavigationController
andUITabBarController
cases. It is working pretty well so far -
Felipe Sabino over 12 yearsthis 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 castingself.navigationController
to this custom class every time you need to check if the controller is presented as modal -
mashdup about 11 yearsWorks perfectly, use if (self.presentingViewController) {//This is a modal viewContoller} else {//This is a normal ViewController}
-
Bart Jacobs almost 11 yearsKeep in mind that the
modalViewController
property is deprecated as of iOS 6. The documentation suggests to usepresentedViewController
instead. -
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 over 10 yearsIMHO, 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 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 about 10 years@oyatek can you use pastebin or something similar and show some code?
-
Roman about 10 years@Feilpe I found the problem -
.parentViewController
is deprecated,.presentingViewController
must be used instead. -
Felipe Sabino about 10 years@oyatek I don't get it... thats exactly why I added the
iOS 5+
fallback with thepresentingViewController
logic... Isn't it working in some specific case you have? -
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 about 10 yearsgood 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 almost 10 yearsDoes not work if parent view controller is a modal on which our view controller is pushed.
-
CocoaBob about 9 yearsThere's a bug, we should check if both sides are nil, because
nil == nil
returnsYES
, and it's not the result we want. -
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 about 9 years@GabrielePetronella Do you mind if I update the answer to also include a Swift implementation of the method?
-
Gabriele Petronella about 9 years@MichaelWaterfall that'd be greatly appreciated, thanks
-
mariusLAN over 8 yearsThere 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 about 8 yearsAlso 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 likeself.presentingViewController?.presentedViewController == parentViewController
. -
isoiphone almost 8 yearsThe 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.