如何从推送的控制器中获取 RootViewController?
Posted
技术标签:
【中文标题】如何从推送的控制器中获取 RootViewController?【英文标题】:How do I get the RootViewController from a pushed controller? 【发布时间】:2010-12-20 01:19:44 【问题描述】:所以,我从 RootViewController 推送一个视图控制器,例如:
[self.navigationController pushViewController:anotherViewController Animation:YES] ;但是,现在来自anotherViewController
,我想再次访问 RootViewController。
我在努力
//(现在在另一个视图控制器中) ///RootViewController *root = (RootViewController*)self.parentViewController ; // 不。 // 呃 RootViewController *root = (RootViewController*)[self.navigationController.viewControllers objectAtIndex:0] ; // 是的!!有用我不确定为什么这样做有效,我不确定这是否是最好的方法。有人可以评论从您推送到该 RootViewController 的 navigationController 的控制器中获取 RootViewController 的更好方法以及我所做的方式是否可靠?
【问题讨论】:
您所做的将可靠地获得根视图控制器(导航层次结构中的第一个),如果您想访问“后退”视图控制器,请参阅我的答案。跨度> See also "What does setting the UIWindow's rootViewController do?" 【参考方案1】:斯威夫特版本:
var rootViewController = self.navigationController?.viewControllers.first
ObjectiveC 版本:
UIViewController *rootViewController = [self.navigationController.viewControllers firstObject];
其中 self 是嵌入在 UINavigationController 中的 UIViewController 的实例。
【讨论】:
我可以从不同的类中获取另一个 ViewController 的 navigationController 吗? 任何 UIViewController 子类都会有一个 navigationController 属性,它指向它的第一个 parentViewController 匹配 UINavigationController 类。【参考方案2】:使用 UINavigationController 的 viewControllers 属性。示例代码:
// Inside another ViewController
NSArray *viewControllers = self.navigationController.viewControllers;
UIViewController *rootViewController = [viewControllers objectAtIndex:viewControllers.count - 2];
这是获取“后退”视图控制器的标准方法。 objectAtIndex:0
起作用的原因是因为您尝试访问的视图控制器也是根视图,如果您在导航中更深入,后视图将与根视图不同。
【讨论】:
:) 泰。它仍然看起来很老套 - :) 我真的想要一个“官方”成员来完成这项工作,比如 self.navigationController.rootViewController,但是唉,没有这样的事情.. 上面的代码是错误的。rootViewController
前面缺少*
,索引应该只是0
。问题中的代码是正确的:RootViewController *root = (RootViewController *)[navigationController.viewControllers objectAtIndex:0]
同意:上面的代码返回 parent 视图控制器,而不是 OP 要求的 root 视图控制器。不过,这就是 Ben S 所说的他会做的事情,他只是没有足够地指出这一点。
第二行应该是:UIViewController *rootViewController = [viewControllers objectAtIndex:viewControllers.count - 1];【参考方案3】:
几乎所有这些答案中都提到了同一件事的稍微不那么丑陋的版本:
UIViewController *rootViewController = [[self.navigationController viewControllers] firstObject];
在你的情况下,我可能会这样做:
在您的 UINavigationController 子类中:
- (UIViewController *)rootViewController
return [[self viewControllers] firstObject];
那么你可以使用:
UIViewController *rootViewController = [self.navigationController rootViewController];
编辑
OP 请求 cmets 中的属性。
如果您愿意,您可以通过 self.navigationController.rootViewController
之类的方式访问它,只需在您的标题中添加一个只读属性即可:
@property (nonatomic, readonly, weak) UIViewController *rootViewController;
【讨论】:
【参考方案4】:对于所有对快速扩展感兴趣的人,这就是我现在正在使用的:
extension UINavigationController
var rootViewController : UIViewController?
return self.viewControllers.first
【讨论】:
谢谢!你也可以删除“as?UIViewController”【参考方案5】:作为@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
【讨论】:
我只是在没有阅读您的答案的情况下添加了这部分,您完全正确,“firstObject”比 [0] 更好【参考方案6】:向UIApplicationsingleton 询问其keyWindow 怎么样,然后从UIWindow 询问根视图控制器(其rootViewController 属性):
UIViewController root = [[[UIApplication sharedApplication] keyWindow] rootViewController];
【讨论】:
如何获取导航控制器? 这是一个错误的建议,如果我的应用程序的 rootviewcontroller 是 UITabBarViewController?【参考方案7】:在这里我想出了从任何地方导航到根目录的通用方法。
您使用该类创建一个新的 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)
)
在项目中的任何地方使用:
...
SharedControllers.navigateToRoot(self)
...
【讨论】:
【参考方案8】:我遇到了一个奇怪的情况。
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(animated:)
时,它会触发navigationController(_:willShow:animated:)
。此时self.viewControllers.first
不是根viewController,它是最后一个会消失的viewController。
总结
self.viewControllers.first
并不总是 root
viewController。有时,它会是最后一个 viewController。
所以,当self.viewControllers
只有一个视图控制器时,我建议按属性保留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)【讨论】:
我也看到了,旧的遗留代码失败了~!!!【参考方案9】:这对我有用:
当我的根视图控制器嵌入导航控制器时:
UINavigationController * navigationController = (UINavigationController *)[[[[UIApplication sharedApplication] windows] firstObject] rootViewController];
RootViewController * rootVC = (RootViewController *)[[navigationController viewControllers] firstObject];
请记住,keyWindow
已弃用。
【讨论】:
以上是关于如何从推送的控制器中获取 RootViewController?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 NSObject 类获取导航控制器并在 ios 中推送视图控制器
在推送通知 Swift 2 AppDelegate 上加载特定的 viewController