所以,我从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,以及我的方式是否可靠?
答案 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)
在这里,我提出了从任何地方导航到根目录的通用方法。
您使用此类创建一个新的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)
...
}
答案 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.first
是root
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
}
}