129
votes

I need an instance of root view controller.

I tried those approaches:

UIViewController *rootViewController = (UIViewController*)[[[UIApplication sharedApplication] keyWindow] rootViewController];

Returns: null:

Also when I try to get an array of controllers:

NSArray *viewControllers = self.navigationController.viewControllers;

It returns only one controller, but it isn't my root view controller.

If I try to take from navigation controller:

UIViewController *root = (UIViewController*)[self.navigationController.viewControllers objectAtIndex:0];

Returns: null:

Any ideas why? What else could I try to get an instance of my root view controller?

Thanks.

8
The keyWindow is the active window,for example,when you show a UIAlertView,the UIAlertView's window is the keyWindow but it's not the AppDelegate's window.If you want to get application's rootViewController,maybe use [[[UIApplication sharedApplication] delegate] window] rootViewController ] is better.无夜之星辰

8 Answers

241
votes

if you are trying to access the rootViewController you set in your appDelegate. try this:

Objective-C

YourViewController *rootController = (YourViewController*)[[(YourAppDelegate*)
                                   [[UIApplication sharedApplication]delegate] window] rootViewController];

Swift

let appDelegate  = UIApplication.sharedApplication().delegate as AppDelegate
let viewController = appDelegate.window!.rootViewController as YourViewController

Swift 3

let appDelegate  = UIApplication.shared.delegate as! AppDelegate
let viewController = appDelegate.window!.rootViewController as! YourViewController

Swift 4 & 4.2

let viewController = UIApplication.shared.keyWindow!.rootViewController as! YourViewController

Swift 5 & 5.1 & 5.2

let viewController = UIApplication.shared.windows.first!.rootViewController as! YourViewController
41
votes

Objective-C

UIViewController *controller = [UIApplication sharedApplication].keyWindow.rootViewController;

Swift 2.0

let viewController = UIApplication.sharedApplication().keyWindow?.rootViewController

Swift 5

let viewController = UIApplication.shared.keyWindow?.rootViewController
10
votes

As suggested here by @0x7fffffff, if you have UINavigationController it can be easier to do:

YourViewController *rootController =
    (YourViewController *)
        [self.navigationController.viewControllers objectAtIndex: 0];

The code in the answer above returns UINavigation controller (if you have it) and if this is what you need, you can use self.navigationController.

5
votes

For Swift 5 and later, I recommend use this method:

UIApplication.shared.windows.last?.rootViewController

Use .last will return top view Controller is active.

.first sometimes doesn't work with libraries that require a window on top & actived.

For example: Admob . I have the ad not showing and find that I am calling the hidden window underneath when using sheet or fullscreenCover.

NOTE: View want to display ads required in NavigationView, if not, ads will be not run.

Example: NavigationView { View1() }

I hope it is useful.

4
votes

Unless you have a good reason, in your root controller do this:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(onTheEvent:)
                                             name:@"ABCMyEvent"
                                           object:nil];

And when you want to notify it:

[[NSNotificationCenter defaultCenter] postNotificationName:@"ABCMyEvent"
                                                object:self];                
2
votes

Swift 3

let rootViewController = UIApplication.shared.keyWindow?.rootViewController
1
votes

Swift way to do it, you can call this from anywhere, it returns optional so watch out about that:

/// EZSwiftExtensions - Gives you the VC on top so you can easily push your popups
var topMostVC: UIViewController? {
    var presentedVC = UIApplication.sharedApplication().keyWindow?.rootViewController
    while let pVC = presentedVC?.presentedViewController {
        presentedVC = pVC
    }

    if presentedVC == nil {
        print("EZSwiftExtensions Error: You don't have any views set. You may be calling them in viewDidLoad. Try viewDidAppear instead.")
    }
    return presentedVC
}

Its included as a standard function in:

https://github.com/goktugyil/EZSwiftExtensions

1
votes

Swift 3: Chage ViewController withOut Segue and send AnyObject Use: Identity MainPageViewController on target ViewController

let mainPage = self.storyboard?.instantiateViewController(withIdentifier: "MainPageViewController") as! MainPageViewController

var mainPageNav = UINavigationController(rootViewController: mainPage)

self.present(mainPageNav, animated: true, completion: nil)

or if you want to Change View Controller and send Data

let mainPage = self.storyboard?.instantiateViewController(withIdentifier: "MainPageViewController") as! MainPageViewController

let dataToSend = "**Any String**" or  var ObjectToSend:**AnyObject** 

mainPage.getData = dataToSend 

var mainPageNav = UINavigationController(rootViewController: mainPage)

self.present(mainPageNav, animated: true, completion: nil)