iOS How to Detect Programmatically When Top View Controller Is Popped

Detect when view controller appears from pop

In view controller B, implement either viewWillAppear or viewDidAppear. In there, use isMovingToParent and isBeingPresented to see under what conditions it is appearing:

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

if !isBeingPresented && !isMovingToParent {
// this view controller is becoming visible because something that was covering it has been dismissed or popped
}
}

Below is a more general use of these properties that people may find handy:

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

if isMovingToParent {
// this view controller is becoming visible because it was just push onto a navigation controller or some other container view controller
} else if isBeingPresented {
// this view controller is becoming visible because it is being presented from another view controller
} else if view.window == nil {
// this view controller is becoming visible for the first time as the window's root view controller
} else {
// this view controller is becoming visible because something that was covering it has been dismissed or popped
}
}

How to check after popping a ViewController, the ViewController on top of the stack, is a particular one?

Inside BaseViewController class:

func goToAOrBViewController() {
guard let navigationController = self.navigationController else { return }
navigationController.popViewController(animated: false)
guard let viewController = navigationController.topViewController else { return }
if viewController is ViewControllerA {
// Do something for A
} else if viewController is ViewControllerB {
// Do Something for B
}
// You need not put else-if case if you are sure BaseVC is reachable from A and B only (just use else)
}

Detecting when a view controller is visible

These four methods can be used in a view controller's appearance callbacks to determine if it is being

presented, dismissed, or added or removed as a child view controller.

@available(iOS 5.0, *)
open var isBeingPresented: Bool { get }

@available(iOS 5.0, *)
open var isBeingDismissed: Bool { get }

@available(iOS 5.0, *)
open var isMovingToParentViewController: Bool { get }

@available(iOS 5.0, *)
open var isMovingFromParentViewController: Bool { get }

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]).

for e.g , you can call the method as

 override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if (self.isMovingFromParentViewController()) {
// we're already on the navigation stack
// another controller must have been popped off
}

}

viewWillDisappear: Determine whether view controller is being popped or is showing a sub-view controller

You can use the following.

- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
NSArray *viewControllers = self.navigationController.viewControllers;
if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
// View is disappearing because a new view controller was pushed onto the stack
NSLog(@"New view controller was pushed");
} else if ([viewControllers indexOfObject:self] == NSNotFound) {
// View is disappearing because it was popped from the stack
NSLog(@"View controller was popped");
}
}

This is, of course, possible because the UINavigationController's view controller stack (exposed through the viewControllers property) has been updated by the time that viewWillDisappear is called.

[iOS]: detect when view controller appears after back from another external app

Setup your view controller to listen for the UIApplicationDidBecomeActiveNotification notification.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(becomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];

Then add the becomeActive: method:

- (void)becomeActive:(NSNotification *)notification {
// App is active again - do something useful
}

And be sure to remove the observer at the appropriate point.

[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];

Of course your app may become active again for lots of reasons, not just returning from the Settings app.

Is there a way to find out whether a view controller is popped off the navigation stack?

UINavigationController has a property viewControllers that contains an array of the view controllers currently on the stack. You could get the array of view controllers and then fetch the next-to-last view controller from that array:

guard let navController = self.navigationController else {
print("We are not part of a navigation stack!")
return
}
let stack = navController.viewControllers
let stackCount = stackCount
if stackCount > 1 {
let nextVC = viewControllers[stackCount - 2]
//nextVC now contains the view controller one down from the current VC
} else {
//We are the root view controller
}

Better way to identify if a viewController was reached by popping the navigationController or using the tab-bar

So to recap, there seems to be no way outside storing the fact that the push was performed as a state. From the answers provided below, this state can be set by implementing the UINavigationControllerDelegate and using the navigationController:willShowViewController:animated:method:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
self.disappearedDueToPush = !(viewController == self);
}

If implementing the delegate seems a bit heavy handed (it did to me) you might up the following in your viewDidDisappear method instead:

if (self != [self.navigationController.viewControllers lastObject]){
self.disappearedDueToPush = YES;
}

This made more sense to me as the reverse logic (and checking towards the fact) is performed in the viewWillAppear method.



Related Topics



Leave a reply



Submit