Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/118.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何从推送的控制器获取RootViewController?_Ios_Iphone_Uinavigationcontroller - Fatal编程技术网

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

Ios 如何从推送的控制器获取RootViewController?,ios,iphone,uinavigationcontroller,Ios,Iphone,Uinavigationcontroller,因此,我从RootViewController推送一个视图控制器,如下所示: [self.navigationController pushViewController:anotherViewController animated:YES] ; 我不确定这为什么有效,也不确定这是否是最好的方法。有人能评论一下从您推入该RootViewController的navigationController的控制器中获取RootViewController的更好方法吗?以及我这样做的方式是否可靠?使用UIN

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

[self.navigationController pushViewController:anotherViewController animated:YES] ; 我不确定这为什么有效,也不确定这是否是最好的方法。有人能评论一下从您推入该RootViewController的navigationController的控制器中获取RootViewController的更好方法吗?以及我这样做的方式是否可靠?

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

// Inside another ViewController
NSArray *viewControllers = self.navigationController.viewControllers;
UIViewController *rootViewController = [viewControllers objectAtIndex:viewControllers.count - 2];
这是获取“返回”视图控制器的标准方法。之所以
objectAtIndex:0
有效,是因为您尝试访问的视图控制器也是根视图控制器,如果您在导航中更深入,则后视图将与根视图不同。

Swift版本:

var rootViewController = self.navigationController?.viewControllers.first
UIViewController *rootViewController = [self.navigationController.viewControllers firstObject];
ObjectiveC版本:

var rootViewController = self.navigationController?.viewControllers.first
UIViewController *rootViewController = [self.navigationController.viewControllers firstObject];
其中self是嵌入在UINavigationController中的UIViewController的实例。

如何请求其,并从中请求根视图控制器(其属性):

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
    }

}

几乎所有这些答案中都提到了同样的事情的一个稍微不那么丑陋的版本:

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;
作为对答案的补充,在
objectAtIndex:0
上使用
firstObject
始终是一种很好的方法,因为如果数组中没有对象,第一个将返回nil,而后一个将抛出异常

UIViewController *rootViewController = self.navigationController.rootViewController;
或者,创建一个名为
UINavigationController+Additions
的类别,并在其中定义方法,这对您来说是一个巨大的优势

@interface UINavigationController (Additions)

- (UIViewController *)rootViewController;

@end

@implementation UINavigationController (Additions)

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

@end

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

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

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

  • 使用该类创建新的类文件,以便可以从项目中的任何位置访问它:

    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)
                })
            }
        }
    }
    
    {
        ...
        SharedControllers.navigateToRoot(self)
        ...
    }
    
  • 从项目中的任何位置使用:

    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)
                })
            }
        }
    }
    
    {
        ...
        SharedControllers.navigateToRoot(self)
        ...
    }
    
  • 这对我很有用: 当我的根视图控制器嵌入到导航控制器中时:

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

    请记住,
    keyWindow
    已被弃用

    我遇到了一种奇怪的情况

    self.viewControllers.first
    不总是根viewController

    通常,
    self.viewControllers.first实际上是根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.first
    root
    viewController。 但是,当我调用
    popToRootViewController(动画:)
    ,然后它触发
    navigationController(quo;:将显示:动画:)
    。此时,
    self.viewControllers.first
    不是根viewController,它是将消失的最后一个viewController

    总结
    • self.viewController.first
      并不总是
      root
      viewController。有时,它将是最后一个viewController
    因此,当
    self.viewControllers
    只有一个viewController时,我建议按属性保留
    rootViewController
    。我在自定义UINavigationController的
    viewDidLoad()
    中获取根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)

    您所做的将可靠地获得根视图控制器(导航层次结构中的第一个),如果您想访问“后退”视图控制器,请参阅我的答案。:)ty。这看起来还是有点不对劲——:)我真的很想让一个“官方”成员来做这项工作,比如self.navigationController.rootViewController,但是,唉,没有这样的事情……上面的代码是错误的
    rootViewController
    前面缺少
    *
    ,索引应为
    0
    。问题中的代码是正确的:
    RootViewController*root=(RootViewController*)[navigationController.viewControllers objectAtIndex:0]
    同意:上述代码返回父视图控制器,而不是OP要求的根视图控制器。尽管如此,Ben s说他会这么做,但他只是指出得不够。第二行应该是:UIViewController*rootViewController=[viewControllers objectAtIndex:viewControllers.count-1];我只是在没有阅读您的答案的情况下添加了这一部分,您完全正确,“firstObject”比T[0]好。我可以从其他类中获取另一个ViewController的navigationController吗?任何UIViewController子类都将具有navigationController属性,哪一个指向它的第一个parentViewController匹配UINavigationController类。如何获取导航控制器?这是一个错误的建议,因为如果我的应用程序的rootviewcontroller是UITabBarViewController会怎么样?谢谢!您还可以删除“as?UIViewController”我也看到了这一点,旧的遗留代码失败了~!!!