33

I have a view that is UIViewController (root) that handles ads and a UINavigationController. In that UINavigationController I have typical layers of controllers. In my custom settings table view controller, I have a button to contact me for support. When the user clicks this button I create a MFMailComposeViewController and would like to present it. I can't present it from the settings table view as it will be underneath my ads, so I need to reference the root view and present it from there. I've tried self.parentViewController.parentViewController where self is the settings table view, but that doesn't work. How should I reference this. It seems like a bad design to have to reference the root view directly and pass it to the settings view.

1
  • Have you tried self.navigationController? I'm unclear on how your view hierarchy is set up.
    – jaminguy
    May 11, 2011 at 18:19

5 Answers 5

79

Get the current keyWindow:

UIWindow *window = [UIApplication sharedApplication].keyWindow;

Get its rootViewController:

UIViewController *rootViewController = window.rootViewController;

NOTE: If an UIAlertView is currently being shown, a new window is being created and assigned to be the keyWindow. There might be other exceptional cases as well that will not keep your application window to be the keyWindow.

5
  • 1
    This only works on 4.0+ by the way. UIWindow did not have a rootViewController property prior to 4.0. May 11, 2011 at 23:02
  • 1
    @Jesse good point - I am so glad I do not have to support those ancient bricks anymore ;).
    – Till
    May 12, 2011 at 8:33
  • yea, it sucks. i'd say its atleast 50% of my time. May 12, 2011 at 9:17
  • 10
    Just a quick warning. This will not work if its called with a ui alert on screen. May 7, 2013 at 8:05
  • 3
    @ChrisMitchelmore a UIAlert opens a new window, and makes it the key-window as long as it is displayed.
    – Till
    May 7, 2013 at 12:35
33

In my experience, this is the ideal solution to get the rootViewController:

[[[[UIApplication sharedApplication] delegate] window] rootViewController]

Note: In-case of an active UIAlert or UIActionSheet, you get the Alert or Action Sheet as your key window.

3
  • +1 This is the only safe, reliable way to do it. Took ages for me to track down an alert + keyWindow bug, and this post saved me!
    – stonemonk
    Apr 1, 2014 at 0:23
  • 3
    Second that! The keyWindow approach (currently marked as the correct answer) is not reliable, since the key window can change. Aug 14, 2014 at 9:01
  • also had a bug with using the keyWindow during a UIAlertView ... thank you for this! this is the best method to use.
    – manroe
    Jun 3, 2016 at 18:12
2

Use the app singleton. Something like:

[[[UIApplication sharedApplication] delegate] rootViewController] should get it if your viewController that is the root is named rootViewController

1

You can always solve this with 1 line of code but I recommend this Swift way to do it, you can call this from anywhere, its also crash and bug safe:

/// 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

-4

Get the UIApplication object. Cycle through the windows array to find the keyWindow. And then get the rootViewController property.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.