Obtenha o máximo de UIViewController

Eu não consigo obter o melhor UIViewController sem access a um UINavigationController . Aqui está o que eu tenho até agora:

 UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(vc, animated: true, completion: nil) 

No entanto, não parece fazer nada. O keyWindow e o rootViewController parecem ser valores não-nulos, então o encadeamento opcional não deve ser um problema.

Desde já, obrigado!

NOTA: É uma má ideia fazer algo assim. Isso quebra o padrão MVC.

    presentViewController mostra um controlador de visualização. Não retorna um controlador de visualização. Se você não estiver usando um UINavigationController , provavelmente está procurando o UINavigationController e precisará iniciar na raiz e percorrer as exibições apresentadas.

     if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController } // topController should now be your topmost view controller } 

    Para o Swift 3+:

     if var topController = UIApplication.shared.keyWindow?.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController } // topController should now be your topmost view controller } 

    tem essa extensão

    Swift 2. *

     extension UIApplication { class func topViewController(controller: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? { if let navigationController = controller as? UINavigationController { return topViewController(navigationController.visibleViewController) } if let tabController = controller as? UITabBarController { if let selected = tabController.selectedViewController { return topViewController(selected) } } if let presented = controller?.presentedViewController { return topViewController(presented) } return controller } } 

    Swift 3

     extension UIApplication { class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? { if let navigationController = controller as? UINavigationController { return topViewController(controller: navigationController.visibleViewController) } if let tabController = controller as? UITabBarController { if let selected = tabController.selectedViewController { return topViewController(controller: selected) } } if let presented = controller?.presentedViewController { return topViewController(controller: presented) } return controller } } 

    Você pode usar isso em qualquer lugar no seu controlador

     if let topController = UIApplication.topViewController() { } 
     extension UIWindow { func visibleViewController() -> UIViewController? { if let rootViewController: UIViewController = self.rootViewController { return UIWindow.getVisibleViewControllerFrom(rootViewController) } return nil } class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController { if vc.isKindOfClass(UINavigationController.self) { let navigationController = vc as UINavigationController return UIWindow.getVisibleViewControllerFrom( navigationController.visibleViewController) } else if vc.isKindOfClass(UITabBarController.self) { let tabBarController = vc as UITabBarController return UIWindow.getVisibleViewControllerFrom(tabBarController.selectedViewController!) } else { if let presentedViewController = vc.presentedViewController { return UIWindow.getVisibleViewControllerFrom(presentedViewController!) } else { return vc } } } 

    Uso:

     if let topController = window.visibleViewController() { println(topController) } 

    Para o swift4 encontrar o viewController superior

     extension UIApplication { class func getTopMostViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? { if let nav = base as? UINavigationController { return getTopMostViewController(base: nav.visibleViewController) } if let tab = base as? UITabBarController { if let selected = tab.selectedViewController { return getTopMostViewController(base: selected) } } if let presented = base?.presentedViewController { return getTopMostViewController(base: presented) } return base } } 

    Como usar

     if let topVC = UIApplication.getTopMostViewController() { topVC.view.addSubview(forgotPwdView) } 

    Baseado na resposta de Dianz, a versão Objective-C

     - (UIViewController *) topViewController { UIViewController *baseVC = UIApplication.sharedApplication.keyWindow.rootViewController; if ([baseVC isKindOfClass:[UINavigationController class]]) { return ((UINavigationController *)baseVC).visibleViewController; } if ([baseVC isKindOfClass:[UITabBarController class]]) { UIViewController *selectedTVC = ((UITabBarController*)baseVC).selectedViewController; if (selectedTVC) { return selectedTVC; } } if (baseVC.presentedViewController) { return baseVC.presentedViewController; } return baseVC; } 

    Eu amei a resposta do @dianz , e aqui está a versão do swift 3 dele. É basicamente a mesma coisa, mas a dele não continha uma chave e alguns dos nomes da syntax / variável / método foram alterados. Então aqui está!

     extension UIApplication { class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? { if let nav = base as? UINavigationController { return topViewController(base: nav.visibleViewController) } if let tab = base as? UITabBarController { if let selected = tab.selectedViewController { return topViewController(base: selected) } } if let presented = base?.presentedViewController { return topViewController(base: presented) } return base } } 

    O uso ainda é o mesmo:

     if let topController = UIApplication.topViewController() { print("The view controller you're looking at is: \(topController)") } 

    Use este código para encontrar o melhor UIViewController

     func getTopViewController() -> UIViewController? { var topController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController while topController?.presentedViewController != nil { topController = topController?.presentedViewController } return topController } 

    você pode definir uma variável UIViewController em AppDelegate e em cada viewWillAppear definir a variável como self (no entanto, dianz answer é a melhor resposta).

     override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) let appDel = UIApplication.sharedApplication().delegate as! AppDelegate appDel.currentVC = self } 

    Baseado em Bob-c acima:

    Swift 3.0

     extension UIWindow { func visibleViewController() -> UIViewController? { if let rootViewController: UIViewController = self.rootViewController { return UIWindow.getVisibleViewControllerFrom(vc: rootViewController) } return nil } class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController { if vc.isKind(of: UINavigationController.self) { let navigationController = vc as! UINavigationController return UIWindow.getVisibleViewControllerFrom( vc: navigationController.visibleViewController!) } else if vc.isKind(of: UITabBarController.self) { let tabBarController = vc as! UITabBarController return UIWindow.getVisibleViewControllerFrom(vc: tabBarController.selectedViewController!) } else { if let presentedViewController = vc.presentedViewController { return UIWindow.getVisibleViewControllerFrom(vc: presentedViewController) } else { return vc; } } } } 

    Onde você colocou o código?

    Eu tentei o seu código na minha demonstração, eu descobri, se você colocar o código em

     func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 

    falhará, porque a janela principal já foi configurada.

    Mas eu coloquei seu código em algum controlador de visão

     override func viewDidLoad() { 

    Apenas funciona.

    Para encontrar o viewController visível no Swift 3

     if let viewControllers = window?.rootViewController?.childViewControllers { let prefs = UserDefaults.standard if viewControllers[viewControllers.count - 1] is ABCController{ print("[ABCController] is visible") } } 

    Este código encontra o último adicionado ou o último controlador ativo visível.

    Isso eu usei no AppDelegate para encontrar a visão ativa Controller

    https://gist.github.com/db0company/369bfa43cb84b145dfd8 Fiz alguns testes nas respostas e comentários neste site. Para mim, os seguintes trabalhos

     extension UIViewController { func topMostViewController() -> UIViewController { if let presented = self.presentedViewController { return presented.topMostViewController() } if let navigation = self as? UINavigationController { return navigation.visibleViewController?.topMostViewController() ?? navigation } if let tab = self as? UITabBarController { return tab.selectedViewController?.topMostViewController() ?? tab } return self } } extension UIApplication { func topMostViewController() -> UIViewController? { return self.keyWindow?.rootViewController?.topMostViewController() } } 

    Então, pegue o top viewController por:

     UIApplication.shared.topMostViewController()