web-dev-qa-db-fra.com

Obtenez le UIViewController actuellement affiché à l'écran dans AppDelegate.m

La UIViewController actuelle à l'écran doit répondre aux notifications Push des APN en définissant certaines vues de badge. Mais comment pourrais-je obtenir la UIViewController dans methodapplication:didReceiveRemoteNotification: of AppDelegate.m?

J'ai essayé d'utiliser self.window.rootViewController pour obtenir l'affichage actuel UIViewController; il peut s'agir d'un UINavigationViewController ou d'un autre type de contrôleur de vue. Et je découvre que la propriété visibleViewController de UINavigationViewController peut être utilisée pour afficher UIViewController à l'écran. Mais que puis-je faire si ce n’est pas une UINavigationViewController?

Toute aide est appréciée! Le code associé est comme suit.

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

}
112
lu yuan

Vous pouvez également utiliser la variable rootViewController lorsque votre contrôleur n'est pas une variable UINavigationController:

UIViewController *vc = self.window.rootViewController;

Une fois que vous connaissez le contrôleur de vue racine, tout dépend de la manière dont vous avez construit votre interface utilisateur, mais vous pouvez éventuellement trouver un moyen de naviguer dans la hiérarchie des contrôleurs.

Si vous donnez plus de détails sur la façon dont vous avez défini votre application, je pourrais peut-être vous en dire plus.

MODIFIER:

Si vous voulez le plus haut vue (pas voir le contrôleur), vous pouvez vérifier

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

bien que cette vue puisse être invisible ou même couverte par certaines de ses sous-vues ...

encore une fois, cela dépend de votre interface utilisateur, mais cela pourrait aider ...

96
sergio

J'aime toujours les solutions qui impliquent des catégories, car elles sont faciles à utiliser et peuvent être facilement réutilisées.

J'ai donc créé une catégorie sur UIWindow. Vous pouvez maintenant appeler visibleViewController sur UIWindow, ce qui vous permettra d'accéder au contrôleur de vue visible en effectuant une recherche dans la hiérarchie du contrôleur. Cela fonctionne si vous utilisez la navigation et/ou le contrôleur de barre d’onglet. Si vous avez un autre type de contrôleur à suggérer s'il vous plaît faites le moi savoir et je peux l'ajouter.

UIWindow + PazLabs.h (fichier d'en-tête)

#import <UIKit/UIKit.h>

@interface UIWindow (PazLabs)

- (UIViewController *) visibleViewController;

@end

UIWindow + PazLabs.m (fichier d'implémentation)

#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

Version rapide

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

Vous pouvez également envoyer une notification via NSNotificationCenter. Cela vous permet de gérer un certain nombre de situations dans lesquelles la hiérarchie du contrôleur de vue peut être délicate - par exemple, lors de la présentation de modaux, etc.

Par exemple.,

// 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];
}

Dans chacun de vos contrôleurs de vue:

-(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://stackoverflow.com/a/2777460/305149
   if (self.isViewLoaded && self.view.window) {
      // handle the notification
   }
}

Vous pouvez également utiliser cette approche pour les contrôles d'instruments devant être mis à jour à la réception d'une notification et utilisés par plusieurs contrôleurs de vue. Dans ce cas, gérez les appels d'observateur d'ajout/suppression dans les méthodes init et dealloc, respectivement. 

37
Aneil Mallavarapu

Extension simple pour UIApplication dans Swift (se soucie même de moreNavigationController dans UITabBarController sur 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
    }
}

Utilisation simple:

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

Fonctionne parfaitement :-)

UPDATE pour le code épuré:

extension UIViewController {
    var top: UIViewController? {
        if let controller = self as? UINavigationController {
            return controller.topViewController?.top
        }
        if let controller = self as? UISplitViewController {
            return controller.viewControllers.last?.top
        }
        if let controller = self as? UITabBarController {
            return controller.selectedViewController?.top
        }
        if let controller = presentedViewController {
            return controller.top
        }
        return self
    }
}
37

Code

Voici une approche utilisant la syntaxe géniale switch-case in 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
        }
    }
}

L'idée de base est la même que dans la réponse de zirinisp, c'est simplement une syntaxe plus semblable à Swift 3.


Usage

Vous voulez probablement créer un fichier nommé UIWindowExtension.Swift. Assurez-vous qu’il inclut l’instruction import UIKit, maintenant copiez le code d’extension ci-dessus .

Du côté des appels, il peut être utilisé sans contrôleur de vue spécifique :

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

Ou si vous savez que votre contrôleur de vue visible est accessible à partir d'un contrôleur de vue spécifique :

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

J'espère que ça aide!

14
Dschee

J'ai trouvé que iOS 8 a tout bousillé. Dans iOS 7, il existe une nouvelle UITransitionView dans la hiérarchie des vues chaque fois que vous avez une version modale UINavigationController. Quoi qu'il en soit, voici mon code qui trouve le meilleur CV. L'appel de getTopMostViewController devrait renvoyer un VC que vous devriez pouvoir envoyer un message tel que presentViewController:animated:completion. Son but est de vous fournir un VC que vous pouvez utiliser pour présenter un VC modal, afin qu'il puisse très probablement s'arrêter et revenir aux classes de conteneur telles que UINavigationController et PAS le VC qu'elles contiennent. Ne devrait pas être difficile d'adapter le code pour le faire aussi. J'ai testé ce code dans diverses situations sous iOS 6, 7 et 8. Merci de me prévenir si vous trouvez des bogues.

+ (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;
}
13
nvrtd frst

Beaucoup moins de code que toutes les autres solutions:

Version Objective-C:

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

    return topViewController;
}

Version Swift 2.0: (merci à Steve.B)

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

Fonctionne n'importe où dans votre application, même avec des modaux.

10
jungledev

Spécifiez le titre de chaque ViewController, puis obtenez le titre du ViewController actuel à l'aide du code indiqué ci-dessous.

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

Puis vérifiez par votre titre comme ça

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

zirinisp's Answer in 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;
            }
        }
    }
}

Usage:

 if let topController = window.visibleViewController() {
            println(topController)
        }
7
Bobj-C

Pourquoi ne pas simplement gérer le code de notification Push dans le délégué de l'application? Est-ce directement lié à une vue?

Vous pouvez vérifier si la vue d'un UIViewController est actuellement visible en vérifiant si sa propriété window de la vue a une valeur. Voir plus ici .

4
Dima

Le mien est meilleur! :)

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
        }
    }
}
4
Nicolas Manzini

Juste addition à @zirinisp répondre.

Créez un fichier, nommez-le UIWindowExtension.Swift et collez l'extrait suivant:

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
}

Utilisez-le n'importe où comme:

if let topVC = getTopViewController() {

}

Merci à @zirinisp.

3
Ashok Kumar S

En ce qui concerne NSNotificationCenter Post ci-dessus (désolé de ne pas savoir où poster un commentaire en dessous ...)

Dans le cas où certains recevaient l'erreur de type - [NSConcreteNotification allKeys]. Change ça:

-(void)didReceiveRemoteNotification:(NSDictionary *)userInfo

pour ça:

-(void)didReceiveRemoteNotification:(NSNotification*)notif {
NSDictionary *dict = notif.userInfo;
}
3
Bseaborn
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
        }
    }
}

Avec cela, vous pouvez facilement obtenir le contrôleur de vue post supérieur comme si

let viewController = UIApplication.topMostViewController

Une chose à noter est que si un UIAlertController est actuellement affiché, UIApplication.topMostViewController renverra une UIAlertController.

2
NSExceptional

Cela a fonctionné pour moi. De nombreuses cibles ayant différents contrôleurs, les réponses précédentes ne semblaient pas fonctionner. 

d'abord, vous voulez ceci dans votre classe AppDelegate:

var window: UIWindow?

alors, dans votre fonction

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

C'est la meilleure façon possible que j'ai essayée. Si cela peut aider quelqu'un ...

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

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

    return topController;
}
1
Mayur Deshmukh

Vérifiez toujours votre configuration de construction si vous exécutez votre application avec debug ou release.

REMARQUE IMPORTANTE: vous ne pouvez pas le tester sans exécuter votre application en mode débogage

C'était ma solution 

1
vikram singh

Swift 2.0 version de la réponse de jungledev

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

J'ai créé une catégorie pour UIApplication avec la propriété visibleViewControllers. L'idée principale est assez simple. J'ai passé en revue les méthodes viewDidAppear et viewDidDisappear dans UIViewController. Dans la méthode viewDidAppear, viewController est ajouté à la pile. Dans viewDidDisappear, la méthode viewController est retirée de la pile. NSPointerArray est utilisé au lieu de NSArray pour stocker les références faibles de UIViewController. Cette approche fonctionne pour toute hiérarchie de 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

Version Swift 3

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

0
Evgeny Mikhaylov