Current view controller from AppDelegate?

Objective CIosUiviewcontroller

Objective C Problem Overview


Is there a way to get the current view controller from the AppDelegate? I know there is rootViewController, but that's not what I'm looking for.

Objective C Solutions


Solution 1 - Objective C

If your app's root view controller is a UINavigationController you can do this:

((UINavigationController*)appDelegate.window.rootViewController).visibleViewController;

Similarly, if it's a UITabBarController you can do this:

((UITabBarController*)appDelegate.window.rootViewController).selectedViewController;

Of course, explicit casting like this is dirty. Better would be to capture the reference yourself using strong types.

Solution 2 - Objective C

This might help

- (UIViewController *)topViewController{
  return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
 
- (UIViewController *)topViewController:(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 topViewController:lastViewController];
  }
  
  UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
  return [self topViewController:presentedViewController];
}

Swift version:

extension UIApplication {
    class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let nav = base as? UINavigationController {
            return topViewController(base: nav.visibleViewController)
        }
        if let tab = base as? UITabBarController {
            if let selected = tab.selectedViewController {
                return topViewController(base: selected)
            }
        }
        if let presented = base?.presentedViewController {
            return topViewController(base: presented)
        }
        return base
    }
}

Taken from: https://gist.github.com/snikch/3661188

Solution 3 - Objective C

If you have UINavigationController into appDelegate then use its property topViewController or visibleViewController

Solution 4 - Objective C

Make an extension:

extension UIApplication {
    class func topViewController(base: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {
        if let nav = base as? UINavigationController {
            return topViewController(nav.visibleViewController)
        }
        if let tab = base as? UITabBarController {
            let moreNavigationController = tab.moreNavigationController

            if let top = moreNavigationController.topViewController where top.view.window != nil {
                return topViewController(top)
            } else if let selected = tab.selectedViewController {
                return topViewController(selected)
            }
        }
        if let presented = base?.presentedViewController {
            return topViewController(presented)
        }
        return base
    }
}

Usage:

if let rootViewController = UIApplication.topViewController() {
    //do sth with root view controller
}

Solution 5 - Objective C

Get the appDelegate object:

MyAppDelegate *tmpDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];

As beryllium suggested you can use the UINavigationController's properties to access your current view controller.

So the code would look like:

id myCurrentController = tmpDelegate.myNavigationController.topViewController;

or:

NSArray *myCurrentViewControllers = tmpDelegate.myNavigationController.viewControllers;

Solution 6 - Objective C

You can get the current view controller from rootViewController by looking for its presentedViewController, like this:

UIViewController *parentViewController = [[[UIApplication sharedApplication] delegate] window].rootViewController;

while (parentViewController.presentedViewController != nil){
    parentViewController = parentViewController.presentedViewController;
}
UIViewController *currentViewController = parentViewController;

It works with me. Hope it helps :)

Solution 7 - Objective C

For anyone not using a UINavigationControllerbut rather their default view controller is a UIViewController you can check which view controller is active (or presented) with the following in AppDelegate:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
    if let rootViewController = self.window!.rootViewController {
        if let presentedViewController = rootViewController.presentedViewController {
            return presentedViewController.supportedInterfaceOrientations()
        }
    } // Else current view controller is DefaultViewController
    
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

As you can see I'm checking for the current view controller in order to support different interface orientations for specific view controllers. For anyone else interested in using this method to support specific the following should be placed in each view controller that needs a specific orientation.

override func supportedInterfaceOrientations() -> Int {
    return Int(UIInterfaceOrientationMask.All.rawValue)
} 

Note: This code was written with Swift 1.2

Solution 8 - Objective C

UIApplication extension in Swift 4+ syntax based on A.G's solution

public extension UIApplication {
    
    class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let nav = base as? UINavigationController {
            return topViewController(base: nav.visibleViewController)
        }
        if let tab = base as? UITabBarController {
            let moreNavigationController = tab.moreNavigationController
            
            if let top = moreNavigationController.topViewController, top.view.window != nil {
                return topViewController(base: top)
            } else if let selected = tab.selectedViewController {
                return topViewController(base: selected)
            }
        }
        if let presented = base?.presentedViewController {
            return topViewController(base: presented)
        }
        return base
    }
}

Sample usage:

if let rootViewController = UIApplication.topViewController() {
     //do something with rootViewController
}

Solution 9 - Objective C

> Swift Solution:

 self.window.rootViewController.presentedViewController. 

That should get you what you need.

Solution 10 - Objective C

Often I need to retrieve the view controller that is currently displayed. It could mean the view controller at the top of the stack of the current UINavigationController, the currently presented view controller, etc. So I wrote this function which figures it out most of the time, and that you can use inside a UIViewController extension.

Code in Swift 3:

func currentViewController(
_ viewController: UIViewController? =
    UIApplication.shared.keyWindow?.rootViewController)
        -> UIViewController? {
    guard let viewController =
    viewController else { return nil }

    if let viewController =
        viewController as? UINavigationController {
        if let viewController =
            viewController.visibleViewController {
            return currentViewController(viewController)
        } else {
            return currentViewController(
                viewController.topViewController)
        }
    } else if let viewController =
            viewController as? UITabBarController {
        if let viewControllers =
            viewController.viewControllers,
            viewControllers.count > 5,
            viewController.selectedIndex >= 4 {
            return currentViewController(
                viewController.moreNavigationController)
        } else {
            return currentViewController(
                viewController.selectedViewController)
        }
    } else if let viewController =
            viewController.presentedViewController {
        return viewController
    } else if viewController.childViewControllers.count > 0 {
        return viewController.childViewControllers[0]
    } else {
        return viewController
    }
}

Call it with: currentViewController()

Solution 11 - Objective C

If anyone wants in Objective C.

GlobalManager.h

//
//  GlobalManager.h
//  Communicator
//
//  Created by Mushrankhan Pathan on 21/10/21.
//  Copyright © 2021 Ribbideo. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface GlobalManager : NSObject

typedef void (^ ActionBlock)(void);

+(UIViewController*)currentController;
+(UIViewController*)currentController:(UIViewController*) baseController;

@end

NS_ASSUME_NONNULL_END

GlobalManager.m

//
//  GlobalManager.m
//  Communicator
//
//  Created by Mushrankhan Pathan on 21/10/21.
//  Copyright © 2021 Ribbideo. All rights reserved.
//

#import "GlobalManager.h"

@implementation GlobalManager

+(UIViewController*)currentController
{
    UIViewController *base = UIApplication.sharedApplication.keyWindow.rootViewController;
    return [GlobalManager currentController:base];
}

+(UIViewController*)currentController:(UIViewController*) baseController
{
    if ([baseController isKindOfClass:[UINavigationController class]]) {
        return [GlobalManager currentController:((UINavigationController*)baseController).visibleViewController];
    }
    
    if ([baseController isKindOfClass:[UITabBarController class]]) {
        UINavigationController* moreNavigationController = ((UITabBarController*)baseController).moreNavigationController;
        UIViewController* top = moreNavigationController.topViewController;
        if (top.view.window != nil) {
            return [GlobalManager currentController:top];
        }
        UIViewController* selectedViewController = ((UITabBarController*)baseController).selectedViewController;
        if (selectedViewController != nil) {
            return [GlobalManager currentController:selectedViewController];
        }
    }
    
    if (baseController.presentedViewController != nil) {
        return [GlobalManager currentController:baseController.presentedViewController];
    }
    
    return baseController;
}

@end

How to use.

UIViewController *currentVC = [GlobalManager currentController];

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionaoakenfoView Question on Stackoverflow
Solution 1 - Objective Cdevios1View Answer on Stackoverflow
Solution 2 - Objective CDaniel RyanView Answer on Stackoverflow
Solution 3 - Objective CberylliumView Answer on Stackoverflow
Solution 4 - Objective CAlvin GeorgeView Answer on Stackoverflow
Solution 5 - Objective CQuasarView Answer on Stackoverflow
Solution 6 - Objective CMattZView Answer on Stackoverflow
Solution 7 - Objective CClay EllisView Answer on Stackoverflow
Solution 8 - Objective CMaverickView Answer on Stackoverflow
Solution 9 - Objective CLevinsonTechnologiesView Answer on Stackoverflow
Solution 10 - Objective CPaolo MusolinoView Answer on Stackoverflow
Solution 11 - Objective CMushrankhanView Answer on Stackoverflow