从应用程序委托获取当前的视图控制器(模态是可能的)

我知道,从应用程序委托获取当前的视图控制器,我可以使用我为我的应用程序设置的navigationController属性。 但是,在我的应用程序的许多地方都可能会出现模态导航控制器。 有没有什么办法来检测这个从应用程序委托,因为当前的导航控制器将不同于应用程序委托持有一个参考?

我build议你使用NSNofiticationCenter。

 //in AppDelegate: @interface AppDelegate() { ... id lastViewController; ... } @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleCurrentViewController) name:@"CurrentViewController" object:nil]; ... } - (void)handleCurrentViewController:(NSNotification *)notification { if([[notification userInfo] objectForKey:@"lastViewController"]) { lastViewController = [[notification userInfo] objectForKey:@"lastViewController"]; } } - (void)applicationDidEnterBackground:(UIApplication *)application { NSLog(@"last view controller is %@", [(UIViewController *)lastViewController class]); } @end //in every ViewController you want to detect @implementation SomeViewController ... - (void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [[NSNotificationCenter defaultCenter] postNotificationName:@"CurrentViewController" object:nil userInfo:[NSDictionary dictionaryWithObjectsAndKeys:self, @"lastViewController", nil]]; } ... @end 

基于这里的要点 ,我做了一个类来获得最顶级的视图控制器,这样调用[[UIApplication sharedApplication] topMostViewController]会给你在你的应用程序中最顶级的视图控制器。

这在iOS 8中特别有用,其中UIAlertViewUIActionSheet已被弃用,而UIAlertController需要在最顶层的视图控制器上显示。

的UIViewController + TopMostViewController.h

 #import <UIKit/UIKit.h> @interface UIViewController (TopMostViewController) - (UIViewController *)topMostViewController; @end @interface UIApplication (TopMostViewController) - (UIViewController *)topMostViewController; @end 

的UIViewController + TopMostViewController.m

 #import "UIViewController+TopMostViewController.h" @implementation UIViewController (TopMostViewController) - (UIViewController *)topMostViewController { if (self.presentedViewController == nil) { return self; } else if ([self.presentedViewController isKindOfClass:[UINavigationController class]]) { UINavigationController *navigationController = (UINavigationController *)self.presentedViewController; UIViewController *lastViewController = [[navigationController viewControllers] lastObject]; return [lastViewController topMostViewController]; } UIViewController *presentedViewController = (UIViewController *)self.presentedViewController; return [presentedViewController topMostViewController]; } @end #pragma mark - @implementation UIApplication (TopMostViewController) - (UIViewController *)topMostViewController { return [self.keyWindow.rootViewController topMostViewController]; } @end 

这对我有效。 我有很多目标有不同的控制器,所以以前的答案似乎没有工作。

首先你需要在你的AppDelegate类中:

 var window: UIWindow? 

然后,在你的function

 let navigationController = window?.rootViewController as? UINavigationController if let activeController = navigationController!.visibleViewController { if activeController.isKindOfClass( MyViewController ) { println("I have found my controller!") } } 

你可以尝试通过做最顶级的观点

 [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject]; 

尽pipe这种观点可能是隐形的,甚至可以被某些子视图所覆盖。

这取决于你的用户界面,但它可能有帮助。

Swift中的很好的解决scheme,在AppDelegate中实现

 func getTopViewController()->UIViewController{ return topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!) } func topViewControllerWithRootViewController(rootViewController:UIViewController)->UIViewController{ if rootViewController is UITabBarController{ let tabBarController = rootViewController as! UITabBarController return topViewControllerWithRootViewController(tabBarController.selectedViewController!) } if rootViewController is UINavigationController{ let navBarController = rootViewController as! UINavigationController return topViewControllerWithRootViewController(navBarController.visibleViewController) } if let presentedViewController = rootViewController.presentedViewController { return topViewControllerWithRootViewController(presentedViewController) } return rootViewController } 

目标 – C

 - (UIViewController*)topViewController { return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; } - (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController { if ([rootViewController isKindOfClass:[UITabBarController class]]) { UITabBarController* tabBarController = (UITabBarController*)rootViewController; return [self topViewControllerWithRootViewController:tabBarController.selectedViewController]; } else if ([rootViewController isKindOfClass:[UINavigationController class]]) { UINavigationController* navigationController = (UINavigationController*)rootViewController; return [self topViewControllerWithRootViewController:navigationController.visibleViewController]; } else if (rootViewController.presentedViewController) { UIViewController* presentedViewController = rootViewController.presentedViewController; return [self topViewControllerWithRootViewController:presentedViewController]; } else { return rootViewController; } } 

如果在App Delegate中有导航控制器,只需使用visibleViewController属性即可。 它会给你可见的控制器,即使它是一个模式。

在swift中,你可以像这样获得活动的ViewController:

  let navigationController = application.windows[0].rootViewController as UINavigationController let activeViewCont = navigationController.visibleViewController 

最好的解决scheme,也moreNavigationControllerUITabBarController moreNavigationController

 extension UIApplication { class func topViewController(base: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? { if let nav = base as? UINavigationController { return topViewController(nav.visibleViewController) } if let tab = base as? UITabBarController { let moreNavigationController = tab.moreNavigationController if let top = moreNavigationController.topViewController where top.view.window != nil { return topViewController(top) } else if let selected = tab.selectedViewController { return topViewController(selected) } } if let presented = base?.presentedViewController { return topViewController(presented) } return base } } 

下面的代码工作得很好。

+(UIViewController *)findBestViewController:(UIViewController *)vc {

 if (vc.presentedViewController) { // Return presented view controller return [AppDelegate findBestViewController:vc.presentedViewController]; } else if ([vc isKindOfClass:[UISplitViewController class]]) { // Return right hand side UISplitViewController* svc = (UISplitViewController*) vc; if (svc.viewControllers.count > 0) return [AppDelegate findBestViewController:svc.viewControllers.lastObject]; else return vc; } else if ([vc isKindOfClass:[UINavigationController class]]) { // Return top view UINavigationController* svc = (UINavigationController*) vc; if (svc.viewControllers.count > 0) return [AppDelegate findBestViewController:svc.topViewController]; else return vc; } else if ([vc isKindOfClass:[UITabBarController class]]) { // Return visible view UITabBarController* svc = (UITabBarController*) vc; if (svc.viewControllers.count > 0) return [AppDelegate findBestViewController:svc.selectedViewController]; else return vc; } else { // Unknown view controller type, return last child view controller return vc; } 

}

+(UIViewController *)currentViewController {

 // Find best view controller UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController; return [AppDelegate findBestViewController:viewController]; 

}

上面的其他解决scheme的工作只是部分复杂的视图层次不处理(导航控制器集成在标签栏控制器,分割视图控制器,视图容器和警报控制器可能会搞砸)。

我通过在AppDelegate中保留当前视图控制器的引用来解决这个问题。 每次出现视图时,我都会利用viewDidAppear(animated:)并在应用程序委托中设置引用。

我知道这个问题是关于Objective-C的,但是我只能提供Swift代码,我相信这对两种types的用户都是有用的。

首先:我已经实现了一个协议来保持事物的清洁和可重用:

 protocol UpdatableViewController { func updateUI() } 

第二:我已经添加了对AppDelegate的引用:

 var currentViewController: UpdatableViewController? 

第三:我在viewDidAppear()中设置当前视图控制器:

 override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate appDelegate?.currentViewController = self } 

第四:

 extension ViewController1: UpdatableViewController { func updateUI() { print("Implement updating here") } }