在当前活动的UIViewController中展示UIAlertController

4
我有一个计时器,当完成后会显示一个警告。 这个警告视图应该在用户当前所在的视图控制器中呈现。
我觉得这可以比以下方法更有效地实现:
现在我正在做的方式是为我的五个视图控制器中的每个都提供一个观察者用于通知以及一个用于创建并呈现该警告的方法。
是否有一种方法只设置一次警告,然后在当前活动的视图控制器中呈现它?
以下是我的代码:
// I've got the following in each of my view controllers.

// In viewDidLoad()
override func viewDidLoad() {
  super.viewDidLoad()
  NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(SonglistViewController.presentSleepTimerFinishedAlert(_:)), name: "presentSleepTimerFinishedAlert", object: nil)
}


func presentTimerFinishedAlert(notification: NSNotification) {
  let alertController = UIAlertController(title: "Timer finished", message: nil, preferredStyle: UIAlertControllerStyle.Alert)
  alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
  presentViewController(alertController, animated: true, completion: nil)
}

非常感谢您提供的任何想法!
3个回答

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

使用这个,您可以轻松地展示您的警告信息,如下所示:

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

需要注意的一点是,如果当前有一个UIAlertController正在显示,UIApplication.topMostViewController将返回一个UIAlertController。在UIAlertController上方呈现具有奇怪的行为,应该避免。因此,在呈现之前,您应该手动检查!(UIApplication.topMostViewController is UIAlertController),或者添加一个else if语句,如果self is UIAlertController则返回nil。

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

1

您可以在导航堆栈中找到顶部的ViewController,并直接从那里呈现AlertController。您可以使用此处发布的扩展方法,在应用程序的任何位置找到顶部ViewController

https://dev59.com/_V8d5IYBdhLWcg3wkS7Y#30858591


1
这取决于您的导航架构。首先,您需要当前VC。如果您将根视图控制器设置为导航控制器并且不显示任何模态,则可以从rootVC获取当前VC。如果您有混合导航,即选项卡栏,然后在其中放置导航控制器,并可能从它们中获取一些模态,则可以在AppDelegate上编写扩展程序,该扩展程序将搜索并返回当前VC。
现在,您应该在某个地方固定此计时器类-它可以是单例或仅被固定在某个位置。然后,在此计时器类中,当计时器结束时,您可以查找当前VC(使用AppDelegate的扩展方法或引用根导航控制器)并在其上呈现警报。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接