iPhone – Cómo encontrar el controlador de vista superior

Me encontré con un par de casos donde sería conveniente poder encontrar el controlador de vista “más alto” (el responsable de la vista actual), pero no he encontrado la forma de hacerlo.

Básicamente, el desafío es este: dado que uno se está ejecutando en una clase que no es un controlador de vista (o una vista) [y no tiene la dirección de una vista activa] y no se ha pasado la dirección del controlador de vista superior ( o, por ejemplo, la dirección del controlador de navegación), ¿es posible encontrar ese controlador de vista? (Y, si es así, ¿cómo?)

O, en su defecto, ¿es posible encontrar la vista superior?

iOS 4 introdujo la propiedad rootViewController en UIWindow:

[UIApplication sharedApplication].keyWindow.rootViewController; 

Sin embargo, deberá configurarlo usted mismo después de crear el controlador de vista.

Creo que necesitas una combinación de la respuesta aceptada y @ fishstix’s

 + (UIViewController*) topMostController { UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController; while (topController.presentedViewController) { topController = topController.presentedViewController; } return topController; } 

Swift 3.0+

 let rootViewController = UIApplication.shared.keyWindow?.rootViewController 

Para completar la respuesta de JonasG (quien omitió los controladores de la barra de tabs al atravesar), aquí está mi versión de devolver el controlador de vista actualmente visible:

 - (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; } } 

Una versión completa no recursiva, que se ocupa de diferentes escenarios:

  • El controlador de vista está presentando otra vista
  • El controlador de vista es un UINavigationController
  • El controlador de vista es un UITabBarController

C objective

  UIViewController *topViewController = self.window.rootViewController; while (true) { if (topViewController.presentedViewController) { topViewController = topViewController.presentedViewController; } else if ([topViewController isKindOfClass:[UINavigationController class]]) { UINavigationController *nav = (UINavigationController *)topViewController; topViewController = nav.topViewController; } else if ([topViewController isKindOfClass:[UITabBarController class]]) { UITabBarController *tab = (UITabBarController *)topViewController; topViewController = tab.selectedViewController; } else { break; } } 

Swift 4+

 extension UIWindow { func topViewController() -> UIViewController? { var top = self.rootViewController while true { if let presented = top?.presentedViewController { top = presented } else if let nav = top as? UINavigationController { top = nav.visibleViewController } else if let tab = top as? UITabBarController { top = tab.selectedViewController } else { break } } return top } } 

Obteniendo la mayor parte del controlador de vista para Swift usando extensiones

Código:

 extension UIViewController { @objc func topMostViewController() -> UIViewController { // Handling Modal views if let presentedViewController = self.presentedViewController { return presentedViewController.topMostViewController() } // Handling UIViewController's added as subviews to some other views. else { for view in self.view.subviews { // Key property which most of us are unaware of / rarely use. if let subViewController = view.next { if subViewController is UIViewController { let viewController = subViewController as! UIViewController return viewController.topMostViewController() } } } return self } } } extension UITabBarController { override func topMostViewController() -> UIViewController { return self.selectedViewController!.topMostViewController() } } extension UINavigationController { override func topMostViewController() -> UIViewController { return self.visibleViewController!.topMostViewController() } } 

Uso:

 UIApplication.sharedApplication().keyWindow!.rootViewController!.topMostViewController() 

Para completar la respuesta de Eric (quien omitió los popovers, los controladores de navegación, los controladores tabbar, los controladores de vista agregados como subvistas a otros controladores de vista al atravesar), aquí está mi versión de devolver el controlador de vista actualmente visible:

=============================================== ===================

 - (UIViewController*)topViewController { return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; } - (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)viewController { if ([viewController isKindOfClass:[UITabBarController class]]) { UITabBarController* tabBarController = (UITabBarController*)viewController; return [self topViewControllerWithRootViewController:tabBarController.selectedViewController]; } else if ([viewController isKindOfClass:[UINavigationController class]]) { UINavigationController* navContObj = (UINavigationController*)viewController; return [self topViewControllerWithRootViewController:navContObj.visibleViewController]; } else if (viewController.presentedViewController && !viewController.presentedViewController.isBeingDismissed) { UIViewController* presentedViewController = viewController.presentedViewController; return [self topViewControllerWithRootViewController:presentedViewController]; } else { for (UIView *view in [viewController.view subviews]) { id subViewController = [view nextResponder]; if ( subViewController && [subViewController isKindOfClass:[UIViewController class]]) { if ([(UIViewController *)subViewController presentedViewController] && ![subViewController presentedViewController].isBeingDismissed) { return [self topViewControllerWithRootViewController:[(UIViewController *)subViewController presentedViewController]]; } } } return viewController; } } 

=============================================== ===================

Y ahora todo lo que necesita hacer para obtener el controlador de vista superior es llamar al método anterior de la siguiente manera:

 UIViewController *topMostViewControllerObj = [self topViewController]; 

Esta respuesta incluye childViewControllers y mantiene una implementación limpia y legible.

 + (UIViewController *)topViewController { UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController; return [rootViewController topVisibleViewController]; } - (UIViewController *)topVisibleViewController { if ([self isKindOfClass:[UITabBarController class]]) { UITabBarController *tabBarController = (UITabBarController *)self; return [tabBarController.selectedViewController topVisibleViewController]; } else if ([self isKindOfClass:[UINavigationController class]]) { UINavigationController *navigationController = (UINavigationController *)self; return [navigationController.visibleViewController topVisibleViewController]; } else if (self.presentedViewController) { return [self.presentedViewController topVisibleViewController]; } else if (self.childViewControllers.count > 0) { return [self.childViewControllers.lastObject topVisibleViewController]; } return self; } 

Hace poco obtuve esta situación en mi proyecto, que requería mostrar una vista de notificación independientemente del controlador que se mostrara y de lo que fuera el tipo (UINavigationController, controlador clásico o controlador de vista personalizado), cuando el estado de la red cambiaba.

Así que juste lanzó mi código, que es bastante fácil y realmente se basa en un protocolo para que sea flexible con cada tipo de controlador de contenedor. Parece estar relacionado con las últimas respuestas, pero de una manera muy flexible.

Puede tomar el código aquí: PPTopMostController

Y obtuve el mejor controlador usando

 UIViewController *c = [UIViewController topMostController]; 

Esto es una mejora a la respuesta de Eric:

 UIViewController *_topMostController(UIViewController *cont) { UIViewController *topController = cont; while (topController.presentedViewController) { topController = topController.presentedViewController; } if ([topController isKindOfClass:[UINavigationController class]]) { UIViewController *visible = ((UINavigationController *)topController).visibleViewController; if (visible) { topController = visible; } } return (topController != cont ? topController : nil); } UIViewController *topMostController() { UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController; UIViewController *next = nil; while ((next = _topMostController(topController)) != nil) { topController = next; } return topController; } 

_topMostController(UIViewController *cont) es una función auxiliar.

¡Ahora todo lo que necesita hacer es llamar a topMostController() y se debe devolver el UIViewController superior!

 - (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; } } 
 @implementation UIWindow (Extensions)

 - (UIViewController *) topMostController
 {
     UIViewController * topController = [self rootViewController];

     while (topController.presentedViewController) {
         topController = topController.presentedViewController;
     }

     return topController;
 }

 @fin

Aquí está mi opinión sobre esto. Gracias a @Stakenborg por señalar la forma de omitir obtener UIAlertView como el controlador más alto

 -(UIWindow *) returnWindowWithWindowLevelNormal { NSArray *windows = [UIApplication sharedApplication].windows; for(UIWindow *topWindow in windows) { if (topWindow.windowLevel == UIWindowLevelNormal) return topWindow; } return [UIApplication sharedApplication].keyWindow; } -(UIViewController *) getTopMostController { UIWindow *topWindow = [UIApplication sharedApplication].keyWindow; if (topWindow.windowLevel != UIWindowLevelNormal) { topWindow = [self returnWindowWithWindowLevelNormal]; } UIViewController *topController = topWindow.rootViewController; if(topController == nil) { topWindow = [UIApplication sharedApplication].delegate.window; if (topWindow.windowLevel != UIWindowLevelNormal) { topWindow = [self returnWindowWithWindowLevelNormal]; } topController = topWindow.rootViewController; } while(topController.presentedViewController) { topController = topController.presentedViewController; } if([topController isKindOfClass:[UINavigationController class]]) { UINavigationController *nav = (UINavigationController*)topController; topController = [nav.viewControllers lastObject]; while(topController.presentedViewController) { topController = topController.presentedViewController; } } return topController; } 

Para la última versión de Swift:
Cree un archivo, UIWindowExtension.swift nombre UIWindowExtension.swift y pegue el siguiente fragmento de UIWindowExtension.swift :

 import UIKit public extension UIWindow { public var visibleViewController: UIViewController? { return UIWindow.getVisibleViewControllerFrom(self.rootViewController) } public static func getVisibleViewControllerFrom(vc: UIViewController?) -> UIViewController? { if let nc = vc as? UINavigationController { return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController) } else if let tc = vc as? UITabBarController { return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController) } else { if let pvc = vc?.presentedViewController { return UIWindow.getVisibleViewControllerFrom(pvc) } else { return vc } } } } func getTopViewController() -> UIViewController? { let appDelegate = UIApplication.sharedApplication().delegate if let window = appDelegate!.window { return window?.visibleViewController } return nil } 

Úselo en cualquier lugar como:

 if let topVC = getTopViewController() { } 

Extensión simple para UIApplication en Swift:

NOTA:

Se preocupa por moreNavigationController dentro de UITabBarController

 extension UIApplication { class func topViewController(baseViewController: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? { if let navigationController = baseViewController as? UINavigationController { return topViewController(navigationController.visibleViewController) } if let tabBarViewController = baseViewController as? UITabBarController { let moreNavigationController = tabBarViewController.moreNavigationController if let topViewController = moreNavigationController.topViewController where topViewController.view.window != nil { return topViewController(topViewController) } else if let selectedViewController = tabBarViewController.selectedViewController { return topViewController(selectedViewController) } } if let splitViewController = baseViewController as? UISplitViewController where splitViewController.viewControllers.count == 1 { return topViewController(splitViewController.viewControllers[0]) } if let presentedViewController = baseViewController?.presentedViewController { return topViewController(presentedViewController) } return baseViewController } } 

Uso simple:

 if let topViewController = UIApplication.topViewController() { //do sth with top view controller } 

Esto es lo que funcionó para mí.

Descubrí que a veces el controlador no estaba en la ventana de la llave, ya que la ventana clave es algo del sistema operativo como una alerta, etc.

  + (UIViewController*)topMostController { UIWindow *topWndow = [UIApplication sharedApplication].keyWindow; UIViewController *topController = topWndow.rootViewController; if (topController == nil) { // The windows in the array are ordered from back to front by window level; thus, // the last window in the array is on top of all other app windows. for (UIWindow *aWndow in [[UIApplication sharedApplication].windows reverseObjectEnumerator]) { topController = aWndow.rootViewController; if (topController) break; } } while (topController.presentedViewController) { topController = topController.presentedViewController; } return topController; } 

Ampliando la respuesta de @ Eric, debe tener cuidado de que la ventana clave sea en realidad la ventana que desea. Si está intentando utilizar este método después de tocar algo en una vista de alerta, por ejemplo, la ventana clave será en realidad la ventana de alerta, y eso le causará problemas sin duda. Esto me sucedió en la naturaleza cuando manejaba enlaces profundos a través de una alerta y causaba SIGABRT sin RASTREO DE PILA. Perra total para depurar.

Aquí está el código que estoy usando ahora:

 - (UIViewController *)getTopMostViewController { UIWindow *topWindow = [UIApplication sharedApplication].keyWindow; if (topWindow.windowLevel != UIWindowLevelNormal) { NSArray *windows = [UIApplication sharedApplication].windows; for(topWindow in windows) { if (topWindow.windowLevel == UIWindowLevelNormal) break; } } UIViewController *topViewController = topWindow.rootViewController; while (topViewController.presentedViewController) { topViewController = topViewController.presentedViewController; } return topViewController; } 

Siéntase libre de mezclar esto con el sabor de recuperar el controlador de vista superior que desee de las otras respuestas a esta pregunta.

Solución alternativa Swift:

 static func topMostController() -> UIViewController { var topController = UIApplication.sharedApplication().keyWindow?.rootViewController while (topController?.presentedViewController != nil) { topController = topController?.presentedViewController } return topController! } 

Otra solución de Swift

 func topController() -> UIViewController? { // recursive follow func follow(from:UIViewController?) -> UIViewController? { if let to = (from as? UITabBarController)?.selectedViewController { return follow(to) } else if let to = (from as? UINavigationController)?.visibleViewController { return follow(to) } else if let to = from?.presentedViewController { return follow(to) } return from } let root = UIApplication.sharedApplication().keyWindow?.rootViewController return follow(root) } 

Esta solución es la más completa. Toma en consideración: UINavigationController UIPageViewController UITabBarController Y el controlador de visualización presentado más arriba desde el controlador de vista superior

El ejemplo está en Swift 3.

Hay 3 sobrecargas

 //Get the topmost view controller for the current application. public func MGGetTopMostViewController() -> UIViewController? { if let currentWindow:UIWindow = UIApplication.shared.keyWindow { return MGGetTopMostViewController(fromWindow: currentWindow) } return nil } //Gets the topmost view controller from a specific window. public func MGGetTopMostViewController(fromWindow window:UIWindow) -> UIViewController? { if let rootViewController:UIViewController = window.rootViewController { return MGGetTopMostViewController(fromViewController: rootViewController) } return nil } //Gets the topmost view controller starting from a specific UIViewController //Pass the rootViewController into this to get the apps top most view controller public func MGGetTopMostViewController(fromViewController viewController:UIViewController) -> UIViewController { //UINavigationController if let navigationViewController:UINavigationController = viewController as? UINavigationController { let viewControllers:[UIViewController] = navigationViewController.viewControllers if navigationViewController.viewControllers.count >= 1 { return MGGetTopMostViewController(fromViewController: viewControllers[viewControllers.count - 1]) } } //UIPageViewController if let pageViewController:UIPageViewController = viewController as? UIPageViewController { if let viewControllers:[UIViewController] = pageViewController.viewControllers { if viewControllers.count >= 1 { return MGGetTopMostViewController(fromViewController: viewControllers[0]) } } } //UITabViewController if let tabBarController:UITabBarController = viewController as? UITabBarController { if let selectedViewController:UIViewController = tabBarController.selectedViewController { return MGGetTopMostViewController(fromViewController: selectedViewController) } } //Lastly, Attempt to get the topmost presented view controller var presentedViewController:UIViewController! = viewController.presentedViewController var nextPresentedViewController:UIViewController! = presentedViewController?.presentedViewController //If there is a presented view controller, get the top most prensentedViewController and return it. if presentedViewController != nil { while nextPresentedViewController != nil { //Set the presented view controller as the next one. presentedViewController = nextPresentedViewController //Attempt to get the next presented view controller nextPresentedViewController = presentedViewController.presentedViewController } return presentedViewController } //If there is no topmost presented view controller, return the view controller itself. return viewController } 

Gran solución en Swift, implementación en 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 } 

Creo que la mayoría de las respuestas han ignorado por completo UINavigationViewController , así que UINavigationViewController este caso de uso con la siguiente implementación.

 + (UIViewController *)topMostController { UIViewController * topController = [UIApplication sharedApplication].keyWindow.rootViewController; while (topController.presentedViewController || [topController isMemberOfClass:[UINavigationController class]]) { if([topController isMemberOfClass:[UINavigationController class]]) { topController = [topController childViewControllers].lastObject; } else { topController = topController.presentedViewController; } } return topController; } 

No estoy seguro si esto ayudará con lo que está tratando de lograr al buscar el controlador de vista superior, pero estaba tratando de presentar un nuevo controlador de vista, pero si mi controlador de vista raíz ya tuviera un diálogo modal, estaría bloqueado, entonces pasaría a la parte superior de todos los controladores de vista modal usando este código:

 UIViewController* parentController =[UIApplication sharedApplication].keyWindow.rootViewController; while( parentController.presentedViewController && parentController != parentController.presentedViewController ) { parentController = parentController.presentedViewController; } 

Rápido:

 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.presentedViewController!) } else { return vc; } } } 

Uso:

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

Las dos funciones siguientes pueden ayudar a encontrar el controlador superior ViewView en la stack de controles. Es posible que necesite una personalización más adelante, pero para este código es increíble entender el concepto de topViewController o stack of viewControllers.

 - (UIViewController*)findTopViewController { id topControler = [self topMostController]; UIViewController* topViewController; if([topControler isKindOfClass:[UINavigationController class]]) { topViewController = [[(UINavigationController*)topControler viewControllers] lastObject]; } else if ([topControler isKindOfClass:[UITabBarController class]]) { //Here you can get reference of top viewcontroller from stack of viewcontrollers on UITabBarController } else { //topController is a preented viewController topViewController = (UIViewController*)topControler; } //NSLog(@"Top ViewController is: %@",NSStringFromClass([topController class])); return topViewController; } - (UIViewController*)topMostController { UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController; while (topController.presentedViewController) { topController = topController.presentedViewController; } //NSLog(@"Top View is: %@",NSStringFromClass([topController class])); return topController; } 

Puede utilizar el método [viewController Class] para averiguar el tipo de clase de un viewController.

Y otra solución Swift

 extension UIViewController { static var topmostViewController: UIViewController? { return UIApplication.sharedApplication().keyWindow?.topmostViewController } var topmostViewController: UIViewController? { return presentedViewController?.topmostViewController ?? self } } extension UINavigationController { override var topmostViewController: UIViewController? { return visibleViewController?.topmostViewController } } extension UITabBarController { override var topmostViewController: UIViewController? { return selectedViewController?.topmostViewController } } extension UIWindow { var topmostViewController: UIViewController? { return rootViewController?.topmostViewController } } 

Muchas de estas respuestas son incompletas. Aunque esto está en Objective-C, esta es la mejor comstackción de todas ellas que podría armar ahora, como un bloque no recursivo:

Enlace a la esencia , en caso de que se revise: https://gist.github.com/benguild/0d149bb3caaabea2dac3d2dca58c0816

Código de referencia / comparación:

 UIViewController *(^topmostViewControllerForFrontmostNormalLevelWindowBlock)(void)=^UIViewController * // NOTE: Adapted from various stray answers here: https://stackoverflow.com/questions/6131205/iphone-how-to-find-topmost-view-controller/20515681 { __block UIViewController *viewController; [[[[[UIApplication sharedApplication] windows] reverseObjectEnumerator] allObjects] enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { if ([window windowLevel]==UIWindowLevelNormal) { viewController=[window rootViewController]; //// *stop=YES; } } ]; while (viewController) { if ([viewController isKindOfClass:[UITabBarController class]]) { viewController=[(UITabBarController *)viewController selectedViewController]; } else if ([viewController isKindOfClass:[UINavigationController class]]) { viewController=[(UINavigationController *)viewController visibleViewController]; } else if ([viewController presentedViewController] && ![[viewController presentedViewController] isBeingDismissed]) { viewController=[viewController presentedViewController]; } else if ([[viewController childViewControllers] count]>0) { viewController=[[viewController childViewControllers] lastObject]; } else { __block BOOL needsRepeat=NO; [[[[[viewController view] subviews] reverseObjectEnumerator] allObjects] enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull view, NSUInteger idx, BOOL * _Nonnull stop) { if ([[view nextResponder] isKindOfClass:[UIViewController class]]) { viewController=(UIViewController *)[view nextResponder]; needsRepeat=YES; //// *stop=YES; } } ]; if (!needsRepeat) { break; } } } return viewController; }; 

If the root controller is a navigation controller, correct way to find top visible controller is:

 UIViewController *rootVC = [[UIApplication sharedApplication] keyWindow].rootViewController; if ([rootVC respondsToSelector:@selector(visibleViewController)]) { UIViewController *topVC = [(UINavigationController *)rootVC visibleViewController]; // do your thing with topVC } 

Here’s an excerpt from UINavigationController.h:

 @property(nonatomic,readonly,retain) UIViewController *topViewController; // The top view controller on the stack. @property(nonatomic,readonly,retain) UIViewController *visibleViewController; // Return modal view controller if it exists. Otherwise the top view controller. 

This works great for finding the top viewController 1 from any root view controlle

 + (UIViewController *)topViewControllerFor:(UIViewController *)viewController { if(!viewController.presentedViewController) return viewController; return [MF5AppDelegate topViewControllerFor:viewController.presentedViewController]; } /* View Controller for Visible View */ AppDelegate *app = [UIApplication sharedApplication].delegate; UIViewController *visibleViewController = [AppDelegate topViewControllerFor:app.window.rootViewController]; 

you could find the top most view controller by using

 NSArray *arrViewControllers=[[self navigationController] viewControllers]; UIViewController *topMostViewController=(UIViewController *)[arrViewControllers objectAtIndex:[arrViewControllers count]-1]; 

Another solution relies on the responder chain, which may or may not work depending on what the first responder is:

  1. Get the first responder .
  2. Get the UIViewController associated with that first responder .

Example pseudo code:

 + (UIViewController *)currentViewController { UIView *firstResponder = [self firstResponder]; // from the first link above, but not guaranteed to return a UIView, so this should be handled more appropriately. UIViewController *viewController = [firstResponder viewController]; // from the second link above return viewController; }