How to get visible viewController from app delegate when using storyboard?

7 Solutions Collect From Internet About “How to get visible viewController from app delegate when using storyboard?”

This should do it for you:

- (void)applicationWillResignActive:(UIApplication *)application
{
    UIViewController *vc = [self visibleViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (UIViewController *)visibleViewController:(UIViewController *)rootViewController
{
    if (rootViewController.presentedViewController == nil)
    {
        return rootViewController;
    }
    if ([rootViewController.presentedViewController isKindOfClass:[UINavigationController class]])
    {
        UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
        UIViewController *lastViewController = [[navigationController viewControllers] lastObject];

        return [self visibleViewController:lastViewController];
    }
    if ([rootViewController.presentedViewController isKindOfClass:[UITabBarController class]])
    {
        UITabBarController *tabBarController = (UITabBarController *)rootViewController.presentedViewController;
        UIViewController *selectedViewController = tabBarController.selectedViewController;

        return [self visibleViewController:selectedViewController];
    }

    UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;

    return [self visibleViewController:presentedViewController];
}

@aviatorken89’s answer worked well for me. I had to translate it to Swift –
for anybody starting out with Swift:

Updated for Swift 3:

func getVisibleViewController(_ rootViewController: UIViewController?) -> UIViewController? {

    var rootVC = rootViewController
    if rootVC == nil {
        rootVC = UIApplication.shared.keyWindow?.rootViewController
    }

    if rootVC?.presentedViewController == nil {
        return rootVC
    }

    if let presented = rootVC?.presentedViewController {
        if presented.isKind(of: UINavigationController.self) {
            let navigationController = presented as! UINavigationController
            return navigationController.viewControllers.last!
        }

        if presented.isKind(of: UITabBarController.self) {
            let tabBarController = presented as! UITabBarController
            return tabBarController.selectedViewController!
        }

        return getVisibleViewController(presented)
    }
    return nil
}

Old answer:

func applicationWillResignActive(application: UIApplication) {
    let currentViewController = getVisibleViewController(nil)
}

func getVisibleViewController(var rootViewController: UIViewController?) -> UIViewController? {

    if rootViewController == nil {
        rootViewController = UIApplication.sharedApplication().keyWindow?.rootViewController
    }

    if rootViewController?.presentedViewController == nil {
        return rootViewController
    }

    if let presented = rootViewController?.presentedViewController {
        if presented.isKindOfClass(UINavigationController) {
            let navigationController = presented as! UINavigationController
            return navigationController.viewControllers.last!
        }

        if presented.isKindOfClass(UITabBarController) {
            let tabBarController = presented as! UITabBarController
            return tabBarController.selectedViewController!
        }

        return getVisibleViewController(presented)
    }
    return nil
}

Here is a recursive, protocol-oriented approach in Swift. Can be extended to custom types but any kind of UIViewController subclass should work with the code below.

public protocol ViewControllerContainer {

    var topMostViewController: UIViewController? { get }
}

extension UIViewController: ViewControllerContainer {

    public var topMostViewController: UIViewController? {

        if let presentedView = presentedViewController {

            return recurseViewController(presentedView)
        }

        return childViewControllers.last.map(recurseViewController)
    }
}

extension UITabBarController {

    public override var topMostViewController: UIViewController? {

        return selectedViewController.map(recurseViewController)
    }
}

extension UINavigationController {

    public override var topMostViewController: UIViewController? {

        return viewControllers.last.map(recurseViewController)
    }
}

extension UIWindow: ViewControllerContainer {

    public var topMostViewController: UIViewController? {

        return rootViewController.map(recurseViewController)
    }
}

func recurseViewController(viewController: UIViewController) -> UIViewController {

    return viewController.topMostViewController.map(recurseViewController) ?? viewController
}

If your app’s root view controller is a UINavigationController than you can use this:

UIViewController *currentControllerName = ((UINavigationController*)appDelegate.window.rootViewController).visibleViewController;

and if you are using UITabBarController than you can use this:

UIViewController *currentControllerName = ((UITabBarController*)appDelegate.window.rootViewController).selectedViewController;

We implemented it as an UIApplication extension:

import UIKit

extension UIApplication {

    var visibleViewController: UIViewController? {

        guard let rootViewController = keyWindow?.rootViewController else {
            return nil
        }

        return getVisibleViewController(rootViewController)
    }

    private func getVisibleViewController(_ rootViewController: UIViewController) -> UIViewController? {

        if let presentedViewController = rootViewController.presentedViewController {
            return getVisibleViewController(presentedViewController)
        }

        if let navigationController = rootViewController as? UINavigationController {
            return navigationController.visibleViewController
        }

        if let tabBarController = rootViewController as? UITabBarController {
            return tabBarController.selectedViewController
        }

        return rootViewController
    }
}

Here’s a Swift 2.3 implementation of @ProgrammierTier’s answer as an extension to a UIViewController

extension UIViewController {
    var visibleViewController: UIViewController? {
        if presentedViewController == nil {
            return self
        }

        if let presented = presentedViewController {
            if presented.isKindOfClass(UINavigationController) {
                let navigationController = presented as! UINavigationController
                return navigationController.viewControllers.last
            }

            if presented.isKindOfClass(UITabBarController) {
                let tabBarController = presented as! UITabBarController
                return tabBarController.selectedViewController
            }

            return presented.visibleViewController
        }

        return nil
    }
}

To get it from applicationWillResignActive

func applicationWillResignActive(application: UIApplication) {
    let visibleVC = application.keyWindow?.rootViewController?.visibleViewController
}

modified from troop231

+ (UIViewController *)visibleViewController:(UIViewController *)rootViewController
{
    if ([rootViewController isKindOfClass:[UINavigationController class]])
    {
        UINavigationController *navigationController = (UINavigationController *)rootViewController;
        UIViewController *lastViewController = [[navigationController viewControllers] lastObject];

        return [self visibleViewController:lastViewController];
    }
    if ([rootViewController isKindOfClass:[UITabBarController class]])
    {
        UITabBarController *tabBarController = (UITabBarController *)rootViewController;
        UIViewController *selectedViewController = tabBarController.selectedViewController;

        return [self visibleViewController:selectedViewController];
    }

    if (rootViewController.presentedViewController != nil)
    {
        UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
        return [self visibleViewController:presentedViewController];
    }

    return rootViewController;
}