如何从推送的控制器获取RootViewController?


137

因此,我从RootViewController推送了一个视图控制器,如下所示:

[self.navigationController pushViewController:anotherViewController动画:是];

但是,从anotherViewController现在开始,我想再次访问RootViewController。

我尝试着

//(现在在anotherViewController内部)
/// RootViewController * root =(RootViewController *)self.parentViewController; //没有
// 呃
RootViewController * root =(RootViewController *)[self.navigationController.viewControllers objectAtIndex:0]; //是的!有用

我不确定为什么这样做,也不确定这是否是最好的方法。有人可以评论从您已推入RootViewController的navigationController的控制器中获取RootViewController的更好方法,以及我所做的方法是否可靠?


您完成的工作将可靠地获得根视图控制器(导航层次结构中的第一个),如果您想访问“后退”视图控制器,请参阅我的回答。
本S

Answers:


133

使用UINavigationController 的viewControllers属性。示例代码:

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

这是获取“后退”视图控制器的标准方法。之所以objectAtIndex:0起作用,是因为您尝试访问的视图控制器也是根视图控制器,如果您在导航中更深入,则后视图将与根视图不同。


6
:) ty。似乎还是很hacky-:)我真的很想让一个“官方”成员来完成这项工作,就像self.navigationController.rootViewController一样,但是可惜,没有这样的事情..
bobobobo

62
上面的代码是错误的。在它之前rootViewController缺少*,索引应该是0。问题中的代码是正确的:RootViewController *root = (RootViewController *)[navigationController.viewControllers objectAtIndex:0]
ma11hew28 2011年

2
同意:上面的代码返回视图控制器,而不是OP要求的视图控制器。尽管如此,Ben S仍会说他会这样做,他只是指出的不够多。
伊凡·武西卡(IvanVučica)2011年

第二行应显示为:UIViewController * rootViewController = [viewControllers objectAtIndex:viewControllers.count-1];
比利

177

迅捷版:

var rootViewController = self.navigationController?.viewControllers.first

ObjectiveC版本:

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

其中self是嵌入在UINavigationController中的UIViewController的实例。


我可以从另一个类中获取另一个ViewController的navigationController吗?
sasquatch 2015年

任何UIViewController子类都将具有navigationController属性,该属性指向它的第一个与UINavigationController类匹配的parentViewController。
dulgan

12

在所有这些答案中几乎都提到了同一个东西的丑陋版本:

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

在您的情况下,我可能会执行以下操作:

在您的UINavigationController子类中

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

那么您可以使用:

UIViewController *rootViewController = [self.navigationController rootViewController];

编辑

OP在评论中要求提供物业。

如果愿意,可以通过self.navigationController.rootViewController将标题中添加一个readonly属性的方式来访问它:

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

8

对于所有对快速扩展感兴趣的人,这就是我现在正在使用的:

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

1
谢谢!您也可以删除“ as?UIViewController”
atereshkov

3

作为@dulgan答案的补充,使用firstObjectover 始终是一个好方法objectAtIndex:0,因为如果数组中没有对象,则第一个返回nil,而后一个抛出异常。

UIViewController *rootViewController = self.navigationController.rootViewController;

另外,对于您来说,创建一个名为的类别UINavigationController+Additions并在其中定义您的方法将是一大优势。

@interface UINavigationController (Additions)

- (UIViewController *)rootViewController;

@end

@implementation UINavigationController (Additions)

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

@end

我只是添加了这部分而没有阅读您的答案,您完全正确,“ firstObject”比[0]好
dulgan 2015年


1

在这里,我想出了一种从任何地方导航到根的通用方法。

  1. 您可以使用该类创建一个新的Class文件,以便可以从项目中的任何位置访问它:

    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)
                })
            }
        }
    }
  2. 项目中任何地方的用法:

    {
        ...
        SharedControllers.navigateToRoot(self)
        ...
    }

0

这对我有用:

当我的根视图控制器嵌入在导航控制器中时:

UINavigationController * navigationController = (UINavigationController *)[[[[UIApplication sharedApplication] windows] firstObject] rootViewController];
RootViewController * rootVC = (RootViewController *)[[navigationController viewControllers] firstObject];

请记住,keyWindow已弃用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.