wake-up-neo.net

Rufen Sie in AppDelegate.m den aktuell angezeigten UIViewController auf dem Bildschirm ab

Das aktuelle UIViewController auf dem Bildschirm muss auf Push-Benachrichtigungen von APNs reagieren, indem einige Badge-Ansichten festgelegt werden. Aber wie kann ich UIViewController in methodapplication:didReceiveRemoteNotification: von AppDelegate.m bekommen?

Ich habe versucht, self.window.rootViewController zu verwenden, um die aktuelle Anzeige UIViewController abzurufen. Dies kann eine UINavigationViewController- oder eine andere Art von View-Controller sein. Und ich finde heraus, dass die visibleViewController-Eigenschaft von UINavigationViewController verwendet werden kann, um UIViewController auf dem Bildschirm anzuzeigen. Aber was kann ich tun, wenn es keine UINavigationViewController ist?

Jede Hilfe wird geschätzt! Der zugehörige Code lautet wie folgt.

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

Sie können die rootViewController auch verwenden, wenn Ihr Controller keine UINavigationController ist:

UIViewController *vc = self.window.rootViewController;

Sobald Sie den Root-View-Controller kennen, hängt er davon ab, wie Sie Ihre Benutzeroberfläche erstellt haben. Möglicherweise finden Sie jedoch einen Weg, um durch die Controller-Hierarchie zu navigieren.

Wenn Sie weitere Details zur Definition Ihrer App angeben, gebe ich möglicherweise weitere Hinweise.

BEARBEITEN:

Wenn Sie den obersten view (nicht view controller) möchten, können Sie dies überprüfen

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

obwohl diese Ansicht möglicherweise nicht sichtbar ist oder sogar durch einige ihrer Unteransichten abgedeckt wird ...

wieder hängt es von Ihrer Benutzeroberfläche ab, aber dies könnte helfen ...

96
sergio

Ich liebe immer Lösungen, die Kategorien beinhalten, da sie fest verankert sind und leicht wiederverwendet werden können.

Also habe ich eine Kategorie auf UIWindow erstellt. Jetzt können Sie visibleViewController unter UIWindow aufrufen. Dadurch erhalten Sie den Sichtbaren Controller, indem Sie die Controller-Hierarchie durchsuchen. Dies funktioniert, wenn Sie einen Navigations- und/oder Registerkarten-Controller verwenden. Wenn Sie eine andere Art von Controller vorschlagen, lass es mich wissen und ich kann es hinzufügen.

UIWindow + PazLabs.h (Header-Datei)

#import <UIKit/UIKit.h>

@interface UIWindow (PazLabs)

- (UIViewController *) visibleViewController;

@end

UIWindow + PazLabs.m (Implementierungsdatei)

#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

Swift Version

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

Sie können auch eine Benachrichtigung über das NSNotificationCenter veröffentlichen. So können Sie mit einer Reihe von Situationen umgehen, in denen das Durchlaufen der View Controller-Hierarchie schwierig sein kann, beispielsweise wenn Modale dargestellt werden usw.

Z.B.,

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

In jedem Ihrer View Controller:

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

Sie können diesen Ansatz auch für Instrumentsteuerelemente verwenden, die aktualisiert werden müssen, wenn eine Benachrichtigung eingeht, und von mehreren Ansichtscontrollern verwendet werden. In diesem Fall müssen Sie die Observer-Aufrufe zum Hinzufügen/Entfernen in den Methoden init und dealloc behandeln. 

37

Einfache Erweiterung für UIApplication in Swift (kümmert sich sogar um moreNavigationController in UITabBarController auf dem 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
    }
}

Einfache Verwendung:

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

Funktioniert perfekt :-)

UPDATE für sauberen Code:

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

Code

Hier ist ein Ansatz, der die großartige Switch-Case-Syntax in Swift 3 verwendet:

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

Die Grundidee ist die gleiche wie in der Antwort von zirinisp. Sie verwendet lediglich eine mehr Swift-3-artige Syntax.


Verwendungszweck

Sie möchten wahrscheinlich eine Datei mit dem Namen UIWindowExtension.Swift erstellen. Stellen Sie sicher, dass die Anweisung import UIKit enthalten ist, jetzt kopieren Sie den obigen Erweiterungscode.

Auf der Anrufseite kann es entweder ohne bestimmten View Controller verwendet werden:

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

Oder wenn Sie wissen, dass Ihr Sicht-Sicht-Controller erreichbar ist von einem bestimmten Sicht-Controller:

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

Ich hoffe, es hilft!

14
Dschee

Ich habe festgestellt, dass iOS 8 alles vermasselt hat. In iOS 7 gibt es immer eine neue UITransitionView in der Ansichtshierarchie, wenn Sie eine modal präsentierte UINavigationController haben. Wie auch immer, hier ist mein Code, der den obersten VC findet. Der Aufruf von getTopMostViewController sollte ein VC zurückgeben, damit Sie eine Nachricht wie presentViewController:animated:completion senden können. Es dient dazu, Ihnen ein VC zu geben, das Sie zur Darstellung eines modalen VC verwenden können, so dass es höchstwahrscheinlich bei Containerklassen wie UINavigationController und NICHT dem darin enthaltenen VC stoppt und zurückkehrt. Es sollte nicht schwer sein, den Code auch dafür anzupassen. Ich habe diesen Code in verschiedenen Situationen in iOS 6, 7 und 8 getestet. Bitte lassen Sie mich wissen, wenn Sie Fehler finden.

+ (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

Weit weniger Code als bei allen anderen Lösungen:

Ziel-C-Version:

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

    return topViewController;
}

Swift 2.0-Version: (Gutschrift geht an Steve.B)

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

Funktioniert überall in Ihrer App, auch mit Modalen.

10
jungledev

Geben Sie den Titel für jeden ViewController an und rufen Sie den Titel des aktuellen ViewControllers anhand des unten angegebenen Codes auf.

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

Dann überprüfen Sie es anhand Ihres Titels so

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

zirinisps Antwort 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;
            }
        }
    }
}

Verwendungszweck:

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

Warum nicht einfach mit dem Push-Benachrichtigungscode im App-Delegierten umgehen? Ist es direkt mit einer Ansicht verbunden?

Sie können prüfen, ob die Ansicht eines UIViewControllers aktuell sichtbar ist, indem Sie prüfen, ob die Eigenschaft window der Ansicht einen Wert hat. Sehen Sie mehr hier .

4
Dima

Meins ist besser! :)

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

Nur die Antwort von @zirinisp.

Erstellen Sie eine Datei, benennen Sie sie UIWindowExtension.Swift und fügen Sie den folgenden Ausschnitt ein:

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
}

Verwenden Sie es überall als:

if let topVC = getTopViewController() {

}

Danke an @zirinisp.

3
Ashok Kumar S

Zum NSNotificationCenter-Beitrag oben (Entschuldigung kann ich nicht herausfinden, wo er einen Kommentar posten sollte ...)

Für den Fall, dass einige den Fehler - [NSConcreteNotification allKeys] erhalten haben. Ändere das:

-(void)didReceiveRemoteNotification:(NSDictionary *)userInfo

zu diesem:

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

Damit können Sie ganz einfach den Top-Post-View-Controller erhalten

let viewController = UIApplication.topMostViewController

Beachten Sie Folgendes: Wenn gerade ein UIAlertController angezeigt wird, gibt UIApplication.topMostViewController eine UIAlertController zurück.

2
NSExceptional

Das hat bei mir funktioniert. Ich habe viele Ziele, die unterschiedliche Controller haben, so dass die vorherigen Antworten nicht funktionierten. 

zuerst möchten Sie dies in Ihrer AppDelegate-Klasse:

var window: UIWindow?

dann in deiner Funktion

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

Dies ist der beste Weg, den ich ausprobiert habe. Wenn es jemandem helfen sollte ...

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

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

    return topController;
}
1
Mayur Deshmukh

Überprüfen Sie immer Ihre Build-Konfiguration, wenn Sie Ihre App mit Debug oder Release ausführen.

WICHTIGER HINWEIS: Sie können es nicht testen, ohne Ihre App im Debug-Modus auszuführen.

Das war meine Lösung 

1
vikram singh

Swift 2.0-Version von Jungledevs Antwort

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

Ich habe eine Kategorie für UIApplication mit der Eigenschaft visibleViewControllers erstellt. Die Grundidee ist ziemlich einfach. Ich habe viewDidAppear- und viewDidDisappear-Methoden in UIViewController durchgebrannt. In viewDidAppear wird viewController zum Stack hinzugefügt. In viewDidDisappear wird viewController vom Stack entfernt. NSPointerArray wird anstelle von NSArray verwendet, um die Referenzen der schwachen UIViewController zu speichern. Dieser Ansatz funktioniert für jede viewControllers-Hierarchie.

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 Version

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