How to present UIAlertController when not in a view controller?

前端 未结 30 3516
庸人自扰
庸人自扰 2020-11-22 06:21

Scenario: The user taps on a button on a view controller. The view controller is the topmost (obviously) in the navigation stack. The tap invokes a utility class method call

30条回答
  •  無奈伤痛
    2020-11-22 06:55

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

    With this you can easily present your alert like so

    UIApplication.topMostViewController?.present(viewController, animated: true, completion: nil)
    

    One thing to note is that if there's a UIAlertController currently being displayed, UIApplication.topMostViewController will return a UIAlertController. Presenting on top of a UIAlertController has weird behavior and should be avoided. As such, you should either manually check that !(UIApplication.topMostViewController is UIAlertController) before presenting, or add an else if case to return nil if self is UIAlertController

    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 if self is UIAlertController {
                return nil
            } else {
                return self
            }
        }
    }
    

提交回复
热议问题