3

Normally I can find out when a View Controller appears with

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
}

This won't be called though if the user presses the home button or for some other reason the app goes to the background and then returns to the foreground. To find out when the app comes to the foreground I can add an observer to the Notification Center.

class FirstViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("FirstViewController")
    }

    @objc func appWillEnterForeground() {
        print("app in foreground")
    }
}

However, my problem is that I have a tabbed app I want to know which View Controller is active when the app comes back into the foreground. The Notification center just sends a general message. Even though I an setting the notification observer in the first tab, it could be on any tab when the app goes into the background.

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • I notice you always use `did`. Have you tried `viewWillAppear`? Maybe `viewWillLoadSubviews`? –  Dec 18 '17 at 06:06
  • are you using a `UITabBarController`? – mugx Dec 18 '17 at 06:17
  • @AndreaMugnaini, yes – Suragch Dec 18 '17 at 06:32
  • @dfd, `viewWillAppear` suffers from the same problem. `viewWillLoadSubviews` shouldn't be called again after the subviews have already been loaded (no new views are loaded when coming from the background). – Suragch Dec 18 '17 at 06:51

2 Answers2

4

NSNotification.Name.UIApplicationWillEnterForeground is a notification thrown by Notification Center. So obviously that is not related to any specific VC. What you can do rather is,

@objc func appWillEnterForeground() {
    if self.viewIfLoaded?.window != nil {
        // viewController is visible
    }
}

Though notification of App entering foreground gets triggered to every viewController observing it, only the VC which is currently loaded and visible will have its code in if condition executed. That gives you a control to decide which VC is currently visible.

EDIT 1:

All that you want to figure out is the top ViewController in navigation stack of TabBarControllerwhen app comes to foreGround, you can add the observer for NSNotification.Name.UIApplicationWillEnterForeground only in UITabBarControllerand in

@objc func appWillEnterForeground() {
    var vc : UIViewController = tabBarController.viewControllers![tabBarController.selectedIndex]
    while vc.presentedViewController != nil || self.childViewControllers.count != 0 {
        if vc.presentedViewController != nil {
            vc = vc.presentedViewController!
        }
        else {
            vc = vc.childViewControllers.last!
        }
    }
    print("\(vc) should be the top most vc")
}
Sandeep Bhandari
  • 19,999
  • 5
  • 45
  • 78
0

Use the Notification Observer and your appWillEnterForeground() or any event which gets fired from the observer in all view controllers under tab controller. So whichever the view controller you came back to will get your notification event get triggered in that particular VC. If you're looking for a centralized solution, this scattered gun approach may not work.

ZameerMoh
  • 1,149
  • 1
  • 17
  • 26
  • 1
    The problem is that all of the tabbed view controllers that have been loaded get notified (and run the `appWillEnterForeground()` method). Sandeep Bhandari's answer showed how to filter out the non visible ones. – Suragch Dec 18 '17 at 06:47