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
Why Is There an Frame Rectangle and an Bounds Rectangle in an Uiview
Why Is My iOS App Not Showing Up in Other Apps' "Open In" Dialog
Find Current Country from iPhone Device
@Published Property Wrapper Not Working on Subclass of Observableobject
How to Manage Cookies with Uiwebview in Swift
Blocks on Swift (Animatewithduration:Animations:Completion:)
Connect Outlet of a Cell Prototype in a Storyboard
How to Remove the Authorization Prompt from Command-Line Instances of Instruments (Xcode)
How to Display the Standard Checkmark on a Uicollectionviewcell
Installing Ffmpeg iOS Libraries Armv7, Armv7S, I386 and Universal on MAC with 10.8
How to Express Strings in Swift Using Unicode Hexadecimal Values (Utf-16)
How to Convert an Uiimage to Grayscale in Swift Using Cifilter
How to Remove Special Characters from String in Swift 2
Uirefreshcontrol on Uicollectionview Only Works If the Collection Fills the Height of the Container