How do I get the RootViewController from a pushed controller?

Solution 1:

Swift version :

var rootViewController = self.navigationController?.viewControllers.first

ObjectiveC version :

UIViewController *rootViewController = [self.navigationController.viewControllers firstObject];

Where self is an instance of a UIViewController embedded in a UINavigationController.

Solution 2:

Use the viewControllers property of the UINavigationController. Example code:

// Inside another ViewController
NSArray *viewControllers = self.navigationController.viewControllers;
UIViewController *rootViewController = [viewControllers objectAtIndex:viewControllers.count - 2];

This is the standard way of getting the "back" view controller. The reason objectAtIndex:0 works is because the view controller you're trying to access is also the root one, if you were deeper in the navigation, the back view would not be the same as the root view.

Solution 3:

A slightly less ugly version of the same thing mentioned in pretty much all these answers:

UIViewController *rootViewController = [[self.navigationController viewControllers] firstObject];

in your case, I'd probably do something like:

inside your UINavigationController subclass:

- (UIViewController *)rootViewController
{
    return [[self viewControllers] firstObject];
}

then you can use:

UIViewController *rootViewController = [self.navigationController rootViewController];

edit

OP asked for a property in the comments.

if you like, you can access this via something like self.navigationController.rootViewController by just adding a readonly property to your header:

@property (nonatomic, readonly, weak) UIViewController *rootViewController;

Solution 4:

For all who are interested in a swift extension, this is what I'm using now:

extension UINavigationController {
    var rootViewController : UIViewController? {
        return self.viewControllers.first
    }
}

Solution 5:

As an addition to @dulgan's answer, it is always a good approach to use firstObject over objectAtIndex:0, because while first one returns nil if there is no object in the array, latter one throws exception.

UIViewController *rootViewController = self.navigationController.rootViewController;

Alternatively, it'd be a big plus for you to create a category named UINavigationController+Additions and define your method in that.

@interface UINavigationController (Additions)

- (UIViewController *)rootViewController;

@end

@implementation UINavigationController (Additions)

- (UIViewController *)rootViewController
{
    return self.viewControllers.firstObject;
}

@end