tab bar iphone ios uiviewcontroller push-notification

iphone - bar - Obtenga el UIViewController que se muestra actualmente en la pantalla en AppDelegate.m



uinavigationbar ios (19)

Código

Aquí hay un enfoque que usa la gran sintaxis de mayúsculas y minúsculas en Swift 3 :

extension UIWindow { /// Returns the currently visible view controller if any reachable within the window. public var visibleViewController: UIViewController? { return UIWindow.visibleViewController(from: rootViewController) } /// Recursively follows navigation controllers, tab bar controllers and modal presented view controllers starting /// from the given view controller to find the currently visible view controller. /// /// - Parameters: /// - viewController: The view controller to start the recursive search from. /// - Returns: The view controller that is most probably visible on screen right now. public static func visibleViewController(from viewController: UIViewController?) -> UIViewController? { switch viewController { case let navigationController as UINavigationController: return UIWindow.visibleViewController(from: navigationController.visibleViewController ?? navigationController.topViewController) case let tabBarController as UITabBarController: return UIWindow.visibleViewController(from: tabBarController.selectedViewController) case let presentingViewController where viewController?.presentedViewController != nil: return UIWindow.visibleViewController(from: presentingViewController?.presentedViewController) default: return viewController } } }

La idea básica es la misma que en la respuesta de zirinisp, simplemente está usando una sintaxis similar a la de Swift 3.

Uso

Probablemente desee crear un archivo llamado UIWindowExtension.swift . Asegúrese de que incluye la import UIKit , ahora copie el código de extensión anterior .

En el lado de la llamada, puede usarse sin ningún controlador de vista específico :

if let visibleViewCtrl = UIApplication.shared.keyWindow?.visibleViewController { // do whatever you want with your `visibleViewCtrl` }

O si sabe que su controlador de vista visible es accesible desde un controlador de vista específico :

if let visibleViewCtrl = UIWindow.visibleViewController(from: specificViewCtrl) { // do whatever you want with your `visibleViewCtrl` }

¡Espero que ayude!

El UIViewController actual en la pantalla debe responder a las notificaciones push desde APN, estableciendo algunas vistas de insignia. Pero ¿cómo podría obtener UIViewController en la application:didReceiveRemoteNotification método application:didReceiveRemoteNotification : de AppDelegate.m ?

Intenté usar self.window.rootViewController para obtener el UIViewController actual, puede ser un UINavigationViewController o algún otro tipo de controlador de vista. Y descubro que la propiedad visibleViewController de UINavigationViewController se puede usar para obtener el UIViewController en la pantalla. Pero, ¿qué podría hacer si no es un UINavigationViewController ?

¡Cualquier ayuda es apreciada! El código relacionado es el siguiente.

AppDelegate.m

... - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { //I would like to find out which view controller is on the screen here. UIViewController *vc = [(UINavigationViewController *)self.window.rootViewController visibleViewController]; [vc performSelector:@selector(handleThePushNotification:) withObject:userInfo]; } ...

ViewControllerA.m

- (void)handleThePushNotification:(NSDictionary *)userInfo{ //set some badge view here }


¡El mío es mejor! :)

extension UIApplication { var visibleViewController : UIViewController? { return keyWindow?.rootViewController?.topViewController } } extension UIViewController { fileprivate var topViewController: UIViewController { switch self { case is UINavigationController: return (self as! UINavigationController).visibleViewController?.topViewController ?? self case is UITabBarController: return (self as! UITabBarController).selectedViewController?.topViewController ?? self default: return presentedViewController?.topViewController ?? self } } }


¿Por qué no manejar el código de notificación de inserción en el delegado de la aplicación? ¿Está directamente relacionado con una vista?

Puede verificar si la vista de UIViewController está actualmente visible al verificar si su propiedad tiene un valor. Ver más here .


En cuanto a NSNotificationCenter Publicar anterior (lo siento no puede encontrar dónde publicar un comentario debajo de él ...)

En caso de que algunos obtengan el error de tipo [NSConcreteNotification allKeys]. Cambia esto:

-(void)didReceiveRemoteNotification:(NSDictionary *)userInfo

a esto:

-(void)didReceiveRemoteNotification:(NSNotification*)notif { NSDictionary *dict = notif.userInfo; }


Especifique el título de cada ViewController y luego obtenga el título de ViewController actual por el código que se indica a continuación.

-(void)viewDidUnload { NSString *currentController = self.navigationController.visibleViewController.title;

Entonces compruébalo por tu título como este

if([currentController isEqualToString:@"myViewControllerTitle"]){ //write your code according to View controller. } }


Esta es la mejor manera posible que he probado. Si debería ayudar a alguien ...

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


Esto funcionó para mí. Tengo muchos objetivos que tienen diferentes controladores, por lo que las respuestas anteriores no parecían funcionar.

primero quiere esto dentro de su clase AppDelegate:

var window: UIWindow?

entonces, en tu función

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


Extensión simple para UIApplication en Swift (se preocupa incluso másNavigationController dentro de UITabBarController en iPhone) :

extension UIApplication { class func topViewController(base: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? { if let nav = base as? UINavigationController { return topViewController(base: 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(base: presented) } return base } }

Uso simple:

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

Funciona perfecto :-)


He descubierto que el iOS 8 ha arruinado todo. En iOS 7 hay una nueva UITransitionView en la jerarquía de vistas siempre que tenga un UINavigationController presentado de forma UINavigationController . De todos modos, aquí está mi código que encuentra obtiene el VC más alto. Llamar a getTopMostViewController debe devolver un VC que le permita enviar un mensaje como presentViewController:animated:completion . Su propósito es conseguirle un VC que pueda usar para presentar un VC modal, por lo que lo más probable es que se detenga y regrese en clases de contenedor como UINavigationController y NO el VC contenido en ellas. No debería ser difícil adaptar el código para hacer eso también. He probado este código en varias situaciones en iOS 6, 7 y 8. Por favor, avíseme si encuentra errores.

+ (UIViewController*) getTopMostViewController { UIWindow *window = [[UIApplication sharedApplication] keyWindow]; if (window.windowLevel != UIWindowLevelNormal) { NSArray *windows = [[UIApplication sharedApplication] windows]; for(window in windows) { if (window.windowLevel == UIWindowLevelNormal) { break; } } } for (UIView *subView in [window subviews]) { UIResponder *responder = [subView nextResponder]; //added this block of code for iOS 8 which puts a UITransitionView in between the UIWindow and the UILayoutContainerView if ([responder isEqual:window]) { //this is a UITransitionView if ([[subView subviews] count]) { UIView *subSubView = [subView subviews][0]; //this should be the UILayoutContainerView responder = [subSubView nextResponder]; } } if([responder isKindOfClass:[UIViewController class]]) { return [self topViewController: (UIViewController *) responder]; } } return nil; } + (UIViewController *) topViewController: (UIViewController *) controller { BOOL isPresenting = NO; do { // this path is called only on iOS 6+, so -presentedViewController is fine here. UIViewController *presented = [controller presentedViewController]; isPresenting = presented != nil; if(presented != nil) { controller = presented; } } while (isPresenting); return controller; }


Mucho menos código que todas las otras soluciones:

Versión Objective-C:

- (UIViewController *)getTopViewController { UIViewController *topViewController = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; while (topViewController.presentedViewController) topViewController = topViewController.presentedViewController; return topViewController; }

Versión Swift 2.0: (el crédito es para Steve.B)

func getTopViewController() -> UIViewController { var topViewController = UIApplication.sharedApplication().delegate!.window!!.rootViewController! while (topViewController.presentedViewController != nil) { topViewController = topViewController.presentedViewController! } return topViewController }

Funciona en cualquier lugar de su aplicación, incluso con modales.


Respuesta de zirinisp en Swift:

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) }


Siempre me encantan las soluciones que involucran categorías ya que están conectadas y pueden reutilizarse fácilmente.

Así que creé una categoría en UIWindow. Ahora puede llamar a visibleViewController en UIWindow y obtendrá el controlador de vista visible buscando en la jerarquía del controlador. Esto funciona si está utilizando un controlador de navegación y / o barra de pestañas. Si tiene otro tipo de controlador que sugerir, hágamelo saber y puedo agregarlo.

UIWindow + PazLabs.h (archivo de encabezado)

#import <UIKit/UIKit.h> @interface UIWindow (PazLabs) - (UIViewController *) visibleViewController; @end

UIWindow + PazLabs.m (archivo de implementación)

#import "UIWindow+PazLabs.h" @implementation UIWindow (PazLabs) - (UIViewController *)visibleViewController { UIViewController *rootViewController = self.rootViewController; return [UIWindow getVisibleViewControllerFrom:rootViewController]; } + (UIViewController *) getVisibleViewControllerFrom:(UIViewController *) vc { if ([vc isKindOfClass:[UINavigationController class]]) { return [UIWindow getVisibleViewControllerFrom:[((UINavigationController *) vc) visibleViewController]]; } else if ([vc isKindOfClass:[UITabBarController class]]) { return [UIWindow getVisibleViewControllerFrom:[((UITabBarController *) vc) selectedViewController]]; } else { if (vc.presentedViewController) { return [UIWindow getVisibleViewControllerFrom:vc.presentedViewController]; } else { return vc; } } } @end

Versión Swift

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


Siempre verifique su configuración de compilación si está ejecutando su aplicación con depuración o versión.

NOTA IMPORTANTE: No puede probarlo sin ejecutar su aplicación en modo de depuración

Esta fue mi solución


Solo agregado a la respuesta de @zirinisp.

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() { }

Gracias a @zirinisp.


Swift 2.0 versión de la respuesta de jungledev

func getTopViewController() -> UIViewController { var topViewController = UIApplication.sharedApplication().delegate!.window!!.rootViewController! while (topViewController.presentedViewController != nil) { topViewController = topViewController.presentedViewController! } return topViewController }


También puede publicar una notificación a través de NSNotificationCenter. Esto permite lidiar con una serie de situaciones donde atravesar la jerarquía del controlador de vista puede ser difícil, por ejemplo, cuando se presentan modales, etc.

P.ej,

// MyAppDelegate.h NSString * const UIApplicationDidReceiveRemoteNotification; // MyAppDelegate.m NSString * const UIApplicationDidReceiveRemoteNotification = @"UIApplicationDidReceiveRemoteNotification"; - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidReceiveRemoteNotification object:self userInfo:userInfo]; }

En cada uno de sus Controladores de Vista:

-(void)viewDidLoad { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveRemoteNotification:) name:UIApplicationDidReceiveRemoteNotification object:nil]; } -(void)viewDidUnload { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveRemoteNotification object:nil]; } -(void)didReceiveRemoteNotification:(NSDictionary *)userInfo { // see http://.com/a/2777460/305149 if (self.isViewLoaded && self.view.window) { // handle the notification } }

También puede usar este enfoque para los controles de instrumentos que necesitan actualizarse cuando se recibe una notificación y son utilizados por varios controladores de vista. En ese caso, maneje las llamadas de observación add / remove en los métodos init y dealloc, respectivamente.


También puede utilizar el rootViewController cuando su controlador no sea un UINavigationController :

UIViewController *vc = self.window.rootViewController;

Una vez que conoce el controlador de vista raíz, depende de cómo haya construido su UI, pero posiblemente pueda encontrar una manera de navegar a través de la jerarquía de controladores.

Si proporciona más detalles sobre la forma en que definió su aplicación, entonces podría darle más pistas.

EDITAR:

Si desea la vista superior (no ver el controlador), puede verificar

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

aunque esta vista puede ser invisible o incluso cubierta por algunas de sus subvistas ...

De nuevo, depende de su UI, pero esto podría ayudar ...


UIApplication una categoría para UIApplication con la propiedad visibleViewControllers . La idea principal es bastante simple. viewDidDisappear métodos viewDidAppear y viewDidDisappear en UIViewController . En el método viewDidAppear viewController se agrega a la pila. En el método viewDidDisappear viewController se elimina de la pila. NSPointerArray se usa en lugar de NSArray para almacenar las UIViewController débiles de UIViewController . Este enfoque funciona para cualquier jerarquía viewControllers.

UIApplication + VisibleViewControllers.h

#import <UIKit/UIKit.h> @interface UIApplication (VisibleViewControllers) @property (nonatomic, readonly) NSArray<__kindof UIViewController *> *visibleViewControllers; @end

UIApplication + VisibleViewControllers.m

#import "UIApplication+VisibleViewControllers.h" #import <objc/runtime.h> @interface UIApplication () @property (nonatomic, readonly) NSPointerArray *visibleViewControllersPointers; @end @implementation UIApplication (VisibleViewControllers) - (NSArray<__kindof UIViewController *> *)visibleViewControllers { return self.visibleViewControllersPointers.allObjects; } - (NSPointerArray *)visibleViewControllersPointers { NSPointerArray *pointers = objc_getAssociatedObject(self, @selector(visibleViewControllersPointers)); if (!pointers) { pointers = [NSPointerArray weakObjectsPointerArray]; objc_setAssociatedObject(self, @selector(visibleViewControllersPointers), pointers, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return pointers; } @end @implementation UIViewController (UIApplication_VisibleViewControllers) + (void)swizzleMethodWithOriginalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector { Method originalMethod = class_getInstanceMethod(self, originalSelector); Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector); BOOL didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if (didAddMethod) { class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } } + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ [self swizzleMethodWithOriginalSelector:@selector(viewDidAppear:) swizzledSelector:@selector(uiapplication_visibleviewcontrollers_viewDidAppear:)]; [self swizzleMethodWithOriginalSelector:@selector(viewDidDisappear:) swizzledSelector:@selector(uiapplication_visibleviewcontrollers_viewDidDisappear:)]; }); } - (void)uiapplication_visibleviewcontrollers_viewDidAppear:(BOOL)animated { [[UIApplication sharedApplication].visibleViewControllersPointers addPointer:(__bridge void * _Nullable)self]; [self uiapplication_visibleviewcontrollers_viewDidAppear:animated]; } - (void)uiapplication_visibleviewcontrollers_viewDidDisappear:(BOOL)animated { NSPointerArray *pointers = [UIApplication sharedApplication].visibleViewControllersPointers; for (int i = 0; i < pointers.count; i++) { UIViewController *viewController = [pointers pointerAtIndex:i]; if ([viewController isEqual:self]) { [pointers removePointerAtIndex:i]; break; } } [self uiapplication_visibleviewcontrollers_viewDidDisappear:animated]; } @end

https://gist.github.com/medvedzzz/e6287b99011f2437ac0beb5a72a897f0

Swift 3 versión

UIApplication + VisibleViewControllers.swift

import UIKit extension UIApplication { private struct AssociatedObjectsKeys { static var visibleViewControllersPointers = "UIApplication_visibleViewControllersPointers" } fileprivate var visibleViewControllersPointers: NSPointerArray { var pointers = objc_getAssociatedObject(self, &AssociatedObjectsKeys.visibleViewControllersPointers) as! NSPointerArray? if (pointers == nil) { pointers = NSPointerArray.weakObjects() objc_setAssociatedObject(self, &AssociatedObjectsKeys.visibleViewControllersPointers, pointers, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } return pointers! } var visibleViewControllers: [UIViewController] { return visibleViewControllersPointers.allObjects as! [UIViewController] } } extension UIViewController { private static func swizzleFunc(withOriginalSelector originalSelector: Selector, swizzledSelector: Selector) { let originalMethod = class_getInstanceMethod(self, originalSelector) let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) if didAddMethod { class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) } else { method_exchangeImplementations(originalMethod, swizzledMethod); } } override open class func initialize() { if self != UIViewController.self { return } let swizzlingClosure: () = { UIViewController.swizzleFunc(withOriginalSelector: #selector(UIViewController.viewDidAppear(_:)), swizzledSelector: #selector(uiapplication_visibleviewcontrollers_viewDidAppear(_:))) UIViewController.swizzleFunc(withOriginalSelector: #selector(UIViewController.viewDidDisappear(_:)), swizzledSelector: #selector(uiapplication_visibleviewcontrollers_viewDidDisappear(_:))) }() swizzlingClosure } @objc private func uiapplication_visibleviewcontrollers_viewDidAppear(_ animated: Bool) { UIApplication.shared.visibleViewControllersPointers.addPointer(Unmanaged.passUnretained(self).toOpaque()) uiapplication_visibleviewcontrollers_viewDidAppear(animated) } @objc private func uiapplication_visibleviewcontrollers_viewDidDisappear(_ animated: Bool) { let pointers = UIApplication.shared.visibleViewControllersPointers for i in 0..<pointers.count { if let pointer = pointers.pointer(at: i) { let viewController = Unmanaged<AnyObject>.fromOpaque(pointer).takeUnretainedValue() as? UIViewController if viewController.isEqual(self) { pointers.removePointer(at: i) break } } } uiapplication_visibleviewcontrollers_viewDidDisappear(animated) } }

https://gist.github.com/medvedzzz/ee6f4071639d987793977dba04e11399


extension UIApplication { /// The top most view controller static var topMostViewController: UIViewController? { return UIApplication.shared.keyWindow?.rootViewController?.visibleViewController } } extension UIViewController { /// The visible view controller from a given view controller var visibleViewController: UIViewController? { if let navigationController = self as? UINavigationController { return navigationController.topViewController?.visibleViewController } else if let tabBarController = self as? UITabBarController { return tabBarController.selectedViewController?.visibleViewController } else if let presentedViewController = presentedViewController { return presentedViewController.visibleViewController } else { return self } } }

Con esto, puedes obtener fácilmente el controlador de vista superior como así

let viewController = UIApplication.topMostViewController

Una cosa a tener en cuenta es que si hay un UIAlertController actualmente en exhibición, UIApplication.topMostViewController devolverá un UIAlertController .