How to get the current displaying UIViewController not in AppDelegate?

16,606

Solution 1

I do not like using this but sometimes it is necessary.

static func getTopViewController() -> UIViewController {

    var viewController = UIViewController()

    if let vc =  UIApplication.shared.delegate?.window??.rootViewController {

        viewController = vc
        var presented = vc

        while let top = presented.presentedViewController {
            presented = top
            viewController = top
        }
    }

    return viewController
}

**EDIT:

Here is an improved version, it will always get top most view controller

static var top: UIViewController? {
    get {
        return topViewController()
    }
}

static var root: UIViewController? {
    get {
        return UIApplication.shared.delegate?.window??.rootViewController
    }
}

static func topViewController(from viewController: UIViewController? = UIViewController.root) -> UIViewController? {
    if let tabBarViewController = viewController as? UITabBarController {
        return topViewController(from: tabBarViewController.selectedViewController)
    } else if let navigationController = viewController as? UINavigationController {
        return topViewController(from: navigationController.visibleViewController)
    } else if let presentedViewController = viewController?.presentedViewController {
        return topViewController(from: presentedViewController)
    } else {
        return viewController
    }
}

Solution 2

Here is the same idea in one function:

func topController(_ parent:UIViewController? = nil) -> UIViewController {
    if let vc = parent {
        if let tab = vc as? UITabBarController, let selected = tab.selectedViewController {
            return topController(selected)
        } else if let nav = vc as? UINavigationController, let top = nav.topViewController {
            return topController(top)
        } else if let presented = vc.presentedViewController {
            return topController(presented)
        } else {
            return vc
        }
    } else {
        return topController(UIApplication.shared.keyWindow!.rootViewController!)
    }
}

works for me in Swift 4 project

Share:
16,606
Pangu
Author by

Pangu

Updated on June 22, 2022

Comments

  • Pangu
    Pangu almost 2 years

    I'm trying to get the currently display UIViewController that is not in the AppDelegate, but it seems to always get the initial top UIViewController, and not the present one.

    The following code in AppDelegate DOES get the current UIViewController present, but this same function does not work when I use it in any one of my View Controllers:

    func getTopViewController() -> UIViewController
    {
        var topViewController = UIApplication.sharedApplication().delegate!.window!!.rootViewController!
        while (topViewController.presentedViewController != nil) {
            topViewController = topViewController.presentedViewController!
        }
        return topViewController
    }
    

    The above code was provided as an answer in a similar question: Get the current displaying UIViewController on the screen in AppDelegate.m

    No matter how deep down I segue to, I can only retrieve the first-most View Controller.

    How can I get the current presenting UIViewController?

    FYI: I'm NOT using a UINavigationController, just regular UIViewController classes.

    • Lefteris
      Lefteris over 7 years
      Are you using a navigation controller ?
    • Pangu
      Pangu over 7 years
      @Lefteris: updated...thanks
  • Pangu
    Pangu over 7 years
    this does not work, I put this in VC2 but it still grabs the top-most VC, i.e. VC1 even though I segued from VC1->VC2
  • Markicevic
    Markicevic over 7 years
    Did you try using debug and "po" to see how you can get VC2?
  • Markicevic
    Markicevic over 7 years
    Enter debug mode in xcode, and you have po ( print object) command in xcode terminal. You can print your current vc and found out how to get to top presented.
  • Markicevic
    Markicevic over 7 years
    This is example how to use po stackoverflow.com/a/11513877/5324438
  • KMC
    KMC about 7 years
    I know it's been like 4 months but could you explain what your code does. It works perfect for me. But I just want to understand how it achieves.
  • Markicevic
    Markicevic about 7 years
    @user30646 I added improved version of this, it just enumerates trough view controller until it finds last one.