【问题标题】:What is the best way to check if a UIAlertController is already presenting?检查 UIAlertController 是否已经呈现的最佳方法是什么?
【发布时间】:2015-03-31 23:00:46
【问题描述】:

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

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

理想情况下,我希望在我的 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
}

根据 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)
    }
}

【问题讨论】:

  • 感谢您发布更新后的代码。
  • 我还将其余代码(设置 UIAlertController 的三行代码)移到 If 语句中,因为它仍然给出以下错误(尝试加载视图控制器的视图,而它是不允许解除分配,可能会导致未定义的行为)
  • 我想参考以下链接的解决方案,请查看stackoverflow.com/a/39994115/1872233

标签: ios uialertcontroller


【解决方案1】:

“已经呈现”的不是 UIAlertController,而是 MessagesMasterVC。一个视图控制器一次只能呈现另一个视图控制器。因此出现错误消息。

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

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

【讨论】:

  • 如果控制器 A 呈现控制器 B,然后 B 想要呈现 UIAlertController,这样可以吗?我遇到了同样的错误,我不知道 B 是否已经在呈现我不知道的东西,或者问题是因为 A 正在呈现 B
  • @ChristopherFrancisco 提出一个新问题!
  • @ChristopherFrancisco 嗨,我现在也有同样的问题,你有没有提出一个新问题?或者你能在哪里解决它?如果是,怎么做?
  • 很好的答案,这是一个微妙的区别。
【解决方案2】:
if ([self.navigationController.visibleViewController isKindOfClass:[UIAlertController class]]) {

      // UIAlertController is presenting.Here

}

【讨论】:

  • 在你的答案中加入一些文字来解释你在做什么总是一个好主意。阅读how to write a good answer
  • 由于缺乏解释,这不是一个很好的答案,但该方法对我有很大帮助 - 问题是我有多个事件调用我的代码来呈现 UIAlertController 连续触发。如果您有类似的问题,请检查此项。
【解决方案3】:

好吧,从我的角度来看,上面建议的解决方案有一个基本问题:

如果你问你的 ViewController,属性 'presentedViewController' 是否为 nil 并且答案是否为 false,你不能得出你的 UIAlertController 已经存在的结论。它可以是任何呈现的 ViewController,例如一个弹出窗口。所以我建议一定要检查一下,Alert 是否已经在屏幕上(将presentedViewController 转换为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")
      }
  }

}

【讨论】:

    【解决方案4】:

    这个分类可以自动管理UIAlertController的所有模态控制器。

    UIViewController+JCPresentQueue.h

    【讨论】:

      【解决方案5】:

      只需关闭当前控制器并呈现您想要的控制器 即

      self.dismiss(animated: false, completion: nil)

      self.displayAlertController()

      【讨论】:

        【解决方案6】:

        这是我在 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)
            }
        }
        

        【讨论】:

        • 好的,这就是我需要的。它也适用于 iOS 13。
        【解决方案7】:

        我们可以简单地检查是否存在任何视图控制器。

        如果出现然后检查它是否是一种 UIAlertController 。

            id alert = self.presentedViewController;
        
            if (alert && [alert isKindOfClass:[UIAlertController class]]) 
              {
                   *// YES UIAlertController is already presented*
              }
            else
               {
                // UIAlertController is not presented OR visible.
               }
        

        【讨论】:

          【解决方案8】:

          我用它来检测、删除和警告。

          首先我们创建一个具有以下功能的警报。

           var yourAlert :UIAlertController!
          
           func useYouAlert (header: String, info:String){
          
          
              yourAlert = UIAlertController(title:header as String, message: info as String, preferredStyle: UIAlertControllerStyle.alert)
          
          
          
              let okAction = UIAlertAction(title: self.langText[62]as String, style: UIAlertActionStyle.default) { (result : UIAlertAction) -> Void in
                  print("OK") 
          
              }
          
          
              yourAlert.addAction(okAction)
              self.present(yourAlert.addAction, animated: true, completion: nil)
          
          }
          

          在你的代码的其他部分

              if yourAlert != nil {
          
                yourAlert.dismiss(animated: true, completion: nil)
          
              }
          

          【讨论】:

            【解决方案9】:

            对于最新的 Swift 语言,您可以使用以下内容:

            var alert = presentedViewController
            
            if alert != nil && (alert is UIAlertController) {
                // YES UIAlertController is already presented*
            } else {
                // UIAlertController is not presented OR visible.
            }
            

            【讨论】:

              【解决方案10】:

              Swift 4.2+ 答案

              if UIApplication.topViewController()!.isKind(of: UIAlertController.self) { 
                          print("UIAlertController is presented")}
              

              对于那些不知道如何获得顶级 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
              }}
              

              Swift 5+ 答案 'keyWindow' 在 iOS 13.0 中已弃用 建议修改

              if UIApplication.topViewController()!.isKind(of: UIAlertController.self) { 
                          print("UIAlertController is presented")}
              

              对于那些不知道如何获得顶级 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
              }}
              

              【讨论】:

                【解决方案11】:

                关闭当前控制器并像这样呈现警报控制器

                 func alert(_ message:String) {
                  let alert = UIAlertController(title: "Error!", message: message, preferredStyle: .alert)
                  alert.addAction(UIAlertAction(title: "Dismiss", style: .default, handler: nil))
                  self.dismiss(animated: false, completion: nil)
                  self.present(alert, animated: true,completion: nil)
                    }
                

                【讨论】:

                  【解决方案12】:

                  您可以在一行中测试是否已显示警报:

                  if self.presentedViewController as? UIAlertController != nil {
                      print ("alert already presented")
                  }
                  

                  【讨论】:

                  • 您可以在答案中解释代码。或者当已经有一个接受或高度评价的答案时它如何添加相关信息阅读how to write a good answer
                  【解决方案13】:

                  我发现我需要创建一个队列来堆叠 UIAlertController 请求。

                  NSMutableArray *errorMessagesToShow; // in @interface
                  errorMessagesToShow=[[NSMutableArray alloc] init];  // in init
                  
                  -(void)showError:(NSString *)theErrorMessage{
                      if(theErrorMessage.length>0){
                          [errorMessagesToShow addObject:theErrorMessage];
                          [self showError1];
                      }
                  }
                  -(void)showError1{
                      NSString *theErrorMessage;
                      if([errorMessagesToShow count]==0)return; // queue finished
                  
                      UIViewController* parentController =[[UIApplication sharedApplication]keyWindow].rootViewController;
                      while( parentController.presentedViewController &&
                        parentController != parentController.presentedViewController ){
                          parentController = parentController.presentedViewController;
                      }
                      if([parentController isKindOfClass:[UIAlertController class]])return;  // busy
                  
                      // construct the alert using [errorMessagesToShow objectAtIndex:0]
                      //  add to each UIAlertAction completionHandler [self showError1];
                      //   then
                  
                      [errorMessagesToShow removeObjectAtIndex:0];
                      [parentController presentViewController:alert animated:YES completion:nil]; 
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2014-01-05
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-12-08
                    • 2013-06-27
                    • 1970-01-01
                    相关资源
                    最近更新 更多