检查UIAlertController是否已经呈现的最佳方法是什么?

hid*_*ame 101 ios uialertcontroller

我有一个tableview,当加载时,每个单元格可能会返回一个NSError,我已经选择在UIAlertController中显示它.问题是如果返回多个错误,我会在控制台中收到此错误.

警告:尝试在MessagesMasterVC上呈现UIAlertController:0x14e64cb00:0x14e53d800已经呈现(null)

理想情况下,我希望在我的UIAlertController扩展方法中处理这个问题.

class func simpleAlertWithMessage(message: String!) -> UIAlertController {

    let alertController = UIAlertController(title: nil, message: message, preferredStyle: UIAlertControllerStyle.Alert)
    let cancel = UIAlertAction(title: "Ok", style: .Cancel, handler: nil)

    alertController.addAction(cancel)
    return alertController
}
Run Code Online (Sandbox Code Playgroud)

基于matt的答案,我将扩展名更改为UIViewController扩展,更加清晰,并节省了大量的presentViewController代码.

    func showSimpleAlertWithMessage(message: String!) {

    let alertController = UIAlertController(title: nil, message: message, preferredStyle: UIAlertControllerStyle.Alert)
    let cancel = UIAlertAction(title: "Ok", style: .Cancel, handler: nil)

    alertController.addAction(cancel)

    if self.presentedViewController == nil {
        self.presentViewController(alertController, animated: true, completion: nil)
    }
}
Run Code Online (Sandbox Code Playgroud)

mat*_*att 109

UIAlertController不是"已经呈现",而是MessagesMasterVC.视图控制器一次只能呈现一个其他视图控制器.因此错误消息.

换句话说,如果您已将视图控制器告知,则presentViewController:...在呈现的视图控制器被解除之前,您无法再次执行此操作.

你可以通过检查它来询问MessagesMasterVC它是否已经呈现了一个视图控制器presentedViewController.如果没有nil,请不要告诉它presentViewController:...- 它已经呈现了一个视图控制器.

  • 如果控制器A出现控制器B,然后B想要呈现UIAlertController,那会起作用吗?我有同样的错误,我无法判断B是否已经呈现了一些我不知道的东西,或者问题是因为B是由A呈现的 (2认同)

小智 29

if ([self.navigationController.visibleViewController isKindOfClass:[UIAlertController class]]) {

      // UIAlertController is presenting.Here

}
Run Code Online (Sandbox Code Playgroud)

  • 在答案中加入一些文字来解释你在做什么总是一个好主意.阅读[如何写出一个好的答案](http://stackoverflow.com/help/how-to-answer). (21认同)

Luk*_*ker 9

那么,从我的观点来看,上面建议的解决方案存在一个基本问题:

如果你问你的ViewController,属性'presentViewController'是否为nil且答案是假的,你不能得出结论,你的UIAlertController已经出现了.它可以是任何呈现的ViewController,例如popOver.所以我的建议是肯定检查,警报是否已经在屏幕上是如下(将presentViewController转换为UIAlertController):

if self.presentedViewController == nil {
   // do your presentation of the UIAlertController
   // ...
} else {
   // either the Alert is already presented, or any other view controller
   // is active (e.g. a PopOver)
   // ...

   let thePresentedVC : UIViewController? = self.presentedViewController as UIViewController?

   if thePresentedVC != nil {
      if let thePresentedVCAsAlertController : UIAlertController = thePresentedVC as? UIAlertController {
         // nothing to do , AlertController already active
         // ...
         print("Alert not necessary, already on the screen !")

      } else {
         // there is another ViewController presented
         // but it is not an UIAlertController, so do 
         // your UIAlertController-Presentation with 
         // this (presented) ViewController
         // ...
         thePresentedVC!.presentViewController(...)

         print("Alert comes up via another presented VC, e.g. a PopOver")
      }
  }
Run Code Online (Sandbox Code Playgroud)

}


bio*_*ker 5

这是我在Swift 3中使用的解决方案。此功能可向用户显示警报,如果您在用户关闭警报之前多次调用该警报,它将在已显示的警报中添加新的警报文本。 。如果显示其他视图,则不会出现警报。并非所有人都同意这种行为,但是在简单情况下它会很好地工作。

extension UIViewController {
    func showAlert(_ msg: String, title: String = "") {
        if let currentAlert = self.presentedViewController as? UIAlertController {
            currentAlert.message = (currentAlert.message ?? "") + "\n\nUpdate:\(title): \(msg)"
            return
        }

        // create the alert
        let alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.alert)
        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))

        // show the alert
        self.present(alert, animated: true, completion: nil)
    }
}
Run Code Online (Sandbox Code Playgroud)


iOS*_*fee 5

斯威夫特 4.2+ 答案

if UIApplication.topViewController()!.isKind(of: UIAlertController.self) { 
            print("UIAlertController is presented")}
Run Code Online (Sandbox Code Playgroud)

对于那些不知道如何获取最顶层 Viewcontroller 的人

extension UIApplication {


public class func topViewController(_ base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
    if let nav = base as? UINavigationController {
        return topViewController(nav.visibleViewController)
    }
    if let tab = base as? UITabBarController {
        if let selected = tab.selectedViewController {
            return topViewController(selected)
        }
    }
    if let presented = base?.presentedViewController {
        return topViewController(presented)
    }
    return base
}}
Run Code Online (Sandbox Code Playgroud)

Swift 5+ 答案 “keyWindow”在 iOS 13.0 中已弃用 建议编辑

if UIApplication.topViewController()!.isKind(of: UIAlertController.self) { 
            print("UIAlertController is presented")}
Run Code Online (Sandbox Code Playgroud)

对于那些不知道如何获取最顶层 Viewcontroller 的人

extension UIApplication {


public class func topViewController(_ base: UIViewController? = UIApplication.shared.windows.first?.rootViewController) -> UIViewController? {
    if let nav = base as? UINavigationController {
        return topViewController(nav.visibleViewController)
    }
    if let tab = base as? UITabBarController {
        if let selected = tab.selectedViewController {
            return topViewController(selected)
        }
    }
    if let presented = base?.presentedViewController {
        return topViewController(presented)
    }
    return base
}}
Run Code Online (Sandbox Code Playgroud)