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

时间:2009-11-24 20:54:42

标签: ios iphone uinavigationcontroller

所以,我从RootViewController推送一个视图控制器,如:

[self.navigationController pushViewController:anotherViewController animated:YES] ;

但是,现在来自anotherViewController,我想再次访问RootViewController。

我正在尝试

// (inside anotherViewController now)
///RootViewController *root = (RootViewController*)self.parentViewController ; // No.
// err
RootViewController *root = (RootViewController*)[self.navigationController.viewControllers objectAtIndex:0] ; // YES!! it works

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

9 个答案:

答案 0 :(得分:165)

Swift版本:

var rootViewController = self.navigationController?.viewControllers.first

ObjectiveC版本:

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

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

答案 1 :(得分:130)

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

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

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

答案 2 :(得分:12)

在所有这些答案中提到的同一件事的稍微不那么丑陋的版本:

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

在你的情况下,我可能会做类似的事情:

你的UINavigationController子类中的

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

然后你可以使用:

UIViewController *rootViewController = [self.navigationController rootViewController];

修改

OP在评论中要求提供房产。

如果您愿意,只需在标头中添加一个只读属性即可通过类似self.navigationController.rootViewController的内容访问此内容:

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

答案 3 :(得分:7)

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

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

答案 4 :(得分:3)

作为@dulgan's答案的补充,在firstObject上使用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

答案 5 :(得分:1)

如何向UIApplication singleton询问其keyWindow,并从UIWindow询问根视图控制器(其rootViewController属性):< / p>

UIViewController root = [[[UIApplication sharedApplication] keyWindow] rootViewController];

答案 6 :(得分: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)
        ...
    }
    

答案 7 :(得分:0)

这对我有用:

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

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

请记住,keyWindow已过时。

答案 8 :(得分:0)

我遇到一个奇怪的情况。

self.viewControllers.first并非始终是root viewController。

通常,self.viewControllers.first实际上是root viewController。但是有时候不是。

class MyCustomMainNavigationController: UINavigationController {

    function configureForView(_ v: UIViewController, animated: Bool) {
        let root = self.viewControllers.first
        let isRoot = (v == root)
    
        // Update UI based on isRoot
        // ....
    }
}

extension MyCustomMainNavigationController: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController, 
        willShow viewController: UIViewController, 
        animated: Bool) {

        self.configureForView(viewController, animated: animated)
    }
}

我的问题:

通常,self.viewControllers.firstroot viewController。 但是,当我调用popToRootViewController(animated:)时,它会触发navigationController(_:willShow:animated:)。目前,self.viewControllers.first不是root viewController,它是最后一个消失的viewController。

摘要

  • self.viewControllers.first并不总是root viewController。有时,它将是最后一个viewController。

因此,当rootViewController仅具有一个viewController时,我建议按属性保留self.viewControllers。我在自定义UINavigationController的viewDidLoad()中获得了root viewController。

class MyCustomMainNavigationController: UINavigationController {
    fileprivate var myRoot: UIViewController!
    override func viewDidLoad() {

        super.viewDidLoad()

        // My UINavigationController is defined in storyboard. 
        // So at this moment, 
        // I can get root viewController by `self.topViewController!`
        let v = self.topViewController!
        self.myRoot = v
    }

}

环境:

  • 具有iOS 14.0.1的iPhone 7
  • Xcode 12.0.1(12A7300)