So, I push a view controller from RootViewController like:
[self.navigationController pushViewController:anotherViewController animated:YES] ;
BUT, FRO
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;
How about asking the UIApplication singleton for its keyWindow, and from that UIWindow ask for the root view controller (its rootViewController property):
UIViewController root = [[[UIApplication sharedApplication] keyWindow] rootViewController];
Here I came up with universal method to navigate from any place to root.
You create a new Class file with this class, so that it's accessible from anywhere in your project:
import UIKit
class SharedControllers
{
static func navigateToRoot(viewController: UIViewController)
{
var nc = viewController.navigationController
// If this is a normal view with NavigationController, then we just pop to root.
if nc != nil
{
nc?.popToRootViewControllerAnimated(true)
return
}
// Most likely we are in Modal view, so we will need to search for a view with NavigationController.
let vc = viewController.presentingViewController
if nc == nil
{
nc = viewController.presentingViewController?.navigationController
}
if nc == nil
{
nc = viewController.parentViewController?.navigationController
}
if vc is UINavigationController && nc == nil
{
nc = vc as? UINavigationController
}
if nc != nil
{
viewController.dismissViewControllerAnimated(false, completion:
{
nc?.popToRootViewControllerAnimated(true)
})
}
}
}
Usage from anywhere in your project:
{
...
SharedControllers.navigateToRoot(self)
...
}
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.
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
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.