Checking if a UIViewController is about to get Popped from a navigation stack?
Solution 1
I don't think there is an explicit message for this, but you could subclass the UINavigationController and override - popViewControllerAnimated (although I haven't tried this before myself).
Alternatively, if there are no other references to the view controller, could you add to its - dealloc?
Solution 2
Override the viewWillDisappear
method in the presented VC, then check the isMovingFromParentViewController
flag within the override and do specific logic. In my case I'm hiding the navigation controllers toolbar. Still requires that your presented VC understand that it was pushed though so not perfect.
Solution 3
Fortunately, by the time the viewWillDisappear method is called, the viewController has already been removed from the stack, so we know the viewController is popping because it's no longer in the self.navigationController.viewControllers
Swift 4
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let nav = self.navigationController {
let isPopping = !nav.viewControllers.contains(self)
if isPopping {
// popping off nav
} else {
// on nav, not popping off (pushing past, being presented over, etc.)
}
} else {
// not on nav at all
}
}
Original Code
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if ((self.navigationController) &&
(![self.navigationController.viewControllers containsObject:self])) {
NSLog(@"I've been popped!");
}
}
Solution 4
Try overriding willMoveToParentViewController:
(instead of viewWillDisappear:
) in your custom subclass of UIViewController
.
Called just before the view controller is added or removed from a container view controller.
- (void)willMoveToParentViewController:(UIViewController *)parent
{
[super willMoveToParentViewController:parent];
if (!parent) {
// `self` is about to get popped.
}
}
Solution 5
This is working for me.
- (void)viewDidDisappear:(BOOL)animated
{
if (self.parentViewController == nil) {
NSLog(@"viewDidDisappear doesn't have parent so it's been popped");
//release stuff here
} else {
NSLog(@"PersonViewController view just hidden");
}
}
Jasarien
iPhone, iPad, Mac OS X Software Engineer based in London, UK. Currently Senior Mobile Software Engineer at Rantmedia. Working on Provenance, a multi-system retro console emulator, in my free time as a labour of love. Blog Twitter Github Provenance
Updated on October 25, 2020Comments
-
Jasarien over 3 years
I need to know when my view controller is about to get popped from a nav stack so I can perform an action.
I can't use -viewWillDisappear, because that gets called when the view controller is moved off screen for ANY reason (like a new view controller being pushed on top).
I specifically need to know when the controller is about to be popped itself.
Any ideas would be awesome, thanks in advance.
-
Max Steinmeyer about 15 yearsThe dealloc will only be called after the pop, though, not before.
-
Jasarien about 15 yearsI don't think that's the best solution. I want to use this controller in other places in the app, and the behaviour I want to execute is specific to this controller and has to happen when the controller is popped. I don't want to have to subclass every navController this viewController appears in.
-
Jasarien about 15 yearsIt seems that this is best solution. It seems to work, so thanks!
-
Alex about 15 yearsTry this: subclass UIViewController, override popViewController:animated: and send a custom message to the UIViewController's delegate. Then, the delegate can decide what it needs to do in each case.
-
grahamparks over 13 yearsThis is exactly what I needed. Thanks.
-
mxcl over 13 yearsMy experimentation suggests that actually
[UINavigationController visibleViewController]
is already set toYourAboutToAppearController
. Though indeed the animation has yet to start. -
Jasarien about 13 yearsAn interesting idea and approach, but I fear it may be slightly too fragile. It relies on an implementation detail that could change at any time.
-
Oded Ben Dov about 13 yearsAgreed, hence that last skepticism.
-
reflog almost 13 yearsThanks Oded, that little snippet helped quite alot!
-
David H over 12 yearsThis is a great solution and not fragile at all as other suggestions. One could also use a Notification so anyone wanting to know about popped views could listen in.
-
HelmiB over 12 yearsSubclassing 'UINavigationController' will lead app to be rejected by apple. documentation
-
Zac Bowling over 12 yearsSubclass will not get you rejected by apple. Class is just not intended for subclassing because apple uses instances of NSNavigaionController that can't get access too, but there is inherently with subclassing.
-
flypig over 11 yearsYes, this would be a good answer, super fast, without delegate, without notification.... thanks. Adding the logic to the viewDidDisapper is not perfect, for example, when pushing or presenting another view controller inside it, the viewDidDisAppear will be invoked too.... This is why I really like this option.
-
flypig over 11 yearsActually, subclass will be a better choice, or there will be a warning, but you can surpress it via: #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" .......... #pragma clang diagnostic pop
-
johndpope over 11 yearsalso there's a side effect with full screen uipopovercontrollers or modal view controllers appearing and triggering these.
-
Ethan about 11 yearsThis is a clean solution in iOS 5+, and who isn't on iOS 5 at this point?
-
Jessedc about 11 yearsUsing the UINavigationControllerDelegate seems like a better option than subclassing UINavigationController.
-
Joshua almost 11 yearsDefinitely the better answer here and one that works at the current time. Removes the need for subclassing, which whilst handy may be a bit over the top for some.
-
Jakob Egger almost 11 yearsCalling
respondsToSelector
is unnecessary.popToRootViewControllerAnimated:
is supported by every UINavigationController. -
Jakob Egger almost 11 yearsAlso, the predicate test is bad. It only checks if a controller with the same class is in the list, not if this specific controller is there. It would be better to use something simpler like:
[self.navigationController.viewControllers containsObject:self]
-
caoimghgin almost 11 yearsJakob Egger is spot on. I've updated code per his suggestions.
-
Pei over 10 yearsFrom Apple doc. "... For example, a view controller can check if it is disappearing because it was dismissed or popped by asking itself in its viewWillDisappear: method by checking the expression ([self isBeingDismissed] || [self isMovingFromParentViewController])"
-
hariseldon78 about 10 years@Alex UIViewController does not have the popViewController:animated: method.
-
tsafrir about 10 yearsThanks @Pei for this comment. I will appreciate if you could add a link to this Apple doc.
-
Pei almost 10 yearsIt's actually from inside iOS SDK documentation. You can find this in line 229 to 232 of UIViewController.h as of Xcode 5.1.1.
-
Ayush Goel over 9 yearsLines have changed to 270-275 as of Xcode 6.1.1 cc: @Pei
-
amergin over 9 yearsThanks Caoimhghin (and a fada over the last i to be precise) (pron: kwee-veen) - although I think I might use MattDiPasquale's override as it's a bit simpler
-
Bamaco almost 9 yearsSounds like this is the way to go! Can't wait to try this. +1
-
Bamaco almost 9 yearsIndeed! why would anyone use viewDidDisappear when it is so much less reliable than willMoveToParentViewController: Using iOS 8.4, I think this should be the accepted answer.
-
ObjSal over 8 yearsAnother good thing about this method is that view controllers still has reference to the navigation controller (if it has one)
-
D6mi over 7 yearsWould like to add that this is not as bulletproof as I first thought. Instead of overriding "willMoveToParentViewController", you should override "didMoveToParentViewController" with the same code inside. The reasoning behind this is that "willMoveToParentViewController" will fire-off even if the user did not COMPLETE the pop using the interactive gesture - you will get a false positive; on the other hand, "didMoveToParentViewController" will not fire until the full transition is complete.
-
Orkhan Alikhanov over 7 yearsIf anyone have freezing issues after using above code, just leave a comment.
-
Anthony Mills almost 7 yearsYou may need to check
isMovingFromParentController
andisBeingDismissed
both for the current view controller and all parents of the current view controller. -
Roi Mulia over 6 yearsShould I have this issue? I don't see it now, but is it a possible bug?
-
Orkhan Alikhanov over 6 years@RoiMulia I had it during swipe gesture. In iOS 9.3.3. Check if you see that issue during swipe.
-
Roi Mulia over 6 yearsThanks, I'll check it closely
-
Roi Mulia over 6 yearsIt's not freezing, but it's not calling UINavigationController popViewController method.. Did you fixed it?
-
Orkhan Alikhanov over 6 years@RoiMulia Hey, I updated the answer with the code I used. Seems that I had added a comment when I wrote the code.
-
SimonTheDiver about 6 yearsalso this fires when the controller appears as well as disappears
-
Simon Moshenko over 4 yearsThank you, your answer really helped me, but it did not work right out of box so I have changed it, and will post another answer.
-
Muhammadjon almost 3 years@Jasarien On the method viewWillDisappear, One can use self.isMovingFromParent variable to check weather it is being popped or not.