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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1792858/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:38:30  来源:igfitidea点击:

How do I get the RootViewController from a pushed controller?

iosiphoneuinavigationcontroller

提问by bobobobo

So, I push a view controller from RootViewController like:

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

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

BUT, FROM anotherViewControllernow, I want to access the RootViewController again.

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

I'm trying

我想

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

I'm not sure WHY this works and I'm not sure if its the best way to do it. Can somebody comment on a better way to get the RootViewController from a controller you've pushed into that RootViewController's navigationController and whether or not the way I've done it is reliable or not?

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

采纳答案by Ben S

Use the viewControllersproperty of the UINavigationController. Example code:

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

// 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:0works 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.

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

回答by dulgan

Swift version :

斯威夫特版:

var rootViewController = self.navigationController?.viewControllers.first

ObjectiveC version :

目标C版本:

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

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

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

回答by Jesse

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:

在您的 UINavigationController 子类中

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

then you can use:

那么你可以使用:

UIViewController *rootViewController = [self.navigationController rootViewController];

edit

编辑

OP asked for a property in the comments.

OP 在评论中要求提供一个属性。

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

如果你愿意,你可以通过类似的self.navigationController.rootViewController方式访问它,只需在你的标题中添加一个只读属性:

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

回答by csch

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

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

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

回答by ozgur

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

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

UIViewController *rootViewController = self.navigationController.rootViewController;

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

或者,创建一个命名的类别UINavigationController+Additions并在其中定义您的方法对您来说是一个很大的优势。

@interface UINavigationController (Additions)

- (UIViewController *)rootViewController;

@end

@implementation UINavigationController (Additions)

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

@end

回答by Maris

Here I came up with universal method to navigate from any place to root.

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

  1. 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)
                })
            }
        }
    }
    
  2. Usage from anywhere in your project:

    {
        ...
        SharedControllers.navigateToRoot(self)
        ...
    }
    
  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)
        ...
    }
    

回答by Basil Bourque

How about asking the UIApplicationsingletonfor its keyWindow, and from that UIWindowask for the root view controller (its rootViewControllerproperty):

如何向UIApplication单例询问其keyWindow,并从该UIWindow询问根视图控制器(其rootViewController属性):

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