【问题标题】:Swift Displaying Alerts best practicesSwift 显示警报最佳实践
【发布时间】:2015-06-20 10:51:32
【问题描述】:

我的应用程序中有各种控制器都需要验证,当验证失败时,我想显示带有错误的警报。是否有一些最佳实践/设计模式可以做到这一点?我可以像这样在 Helper 类中简单地创建一个静态函数:

static func displayAlert(message: String, buttonTitle: String, vc: UIViewController)
{
    let alertController = UIAlertController(title: "", message: message, preferredStyle: .Alert)

    let okAction = UIAlertAction(title: buttonTitle, style: .Default, handler: nil)
    alertController.addAction(okAction)

    vc.presentViewController(alertController, animated: true, completion: nil)
}

但是我需要传递视图控制器..这似乎是不好的做法。我可以发出通知并观察它,但这似乎有点矫枉过正。我是不是想多了,还是有一些更可接受的方式来处理这样的事情?

【问题讨论】:

  • 在这里传入视图控制器很好,比在视图控制器中实现并且无法共享代码要好。我会说你想多了:)
  • 请检查这个全局 UIAlertController 扩展:stackoverflow.com/a/60414319/8201581

标签: ios xcode uialertcontroller


【解决方案1】:

我最终为 UIViewController 创建了一个扩展并在那里创建了警报功能:

extension UIViewController {
  func alert(message: String, title: String = "") {
    let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
    let OKAction = UIAlertAction(title: "OK", style: .default, handler: nil)
    alertController.addAction(OKAction)
    self.present(alertController, animated: true, completion: nil)
  }  
}

【讨论】:

    【解决方案2】:

    斯威夫特 4

    我自己也想要同样的功能,所以我做了一个完整的扩展。要使用它,请在您的项目中创建一个新的 swift 文件并将其命名为您喜欢的任何名称。将以下代码放入:

    import UIKit
    
    extension UIViewController {
    
        func presentAlertWithTitle(title: String, message: String, options: String..., completion: @escaping (Int) -> Void) {
            let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
            for (index, option) in options.enumerated() {
                alertController.addAction(UIAlertAction.init(title: option, style: .default, handler: { (action) in
                    completion(index)
                }))
            }
            self.present(alertController, animated: true, completion: nil)
        }
    }
    

    使用它(很多人实际上并没有展示它,这可能会导致像我这样的新手感到困惑):

    presentAlertWithTitle(title: "Test", message: "A message", options: "1", "2") { (option) in
        print("option: \(option)")
        switch(option) {
            case 0:
                print("option one")
                break
            case 1:
                print("option two")
            default:
                break
        }
    }
    

    【讨论】:

      【解决方案3】:

      作为 https://stackoverflow.com/a/30714429/6822183itstrueimryan 的原始回答

      Swift 3 更新:

      extension UIViewController {
      
          func alert(message: String, title: String = "") {
              let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
              let OKAction = UIAlertAction(title: "OK", style: .default, handler: nil)
              alertController.addAction(OKAction)
              self.present(alertController, animated: true, completion: nil)
          }
      }
      

      【讨论】:

        【解决方案4】:

        我可能已经通过 Krakendev 的一篇文章找到了更好的答案:https://krakendev.io/blog/subclassing-can-suck-and-heres-why

        这个想法是使用面向协议的编程来为 UIViewControllers 创建一个默认的警报实现:

        protocol Alertable {
            func issueAlert()
        }
        
        extension Alertable where Self: UIViewController {
            func issueAlert() {
                // alert code here
            }
        }
        

        现在,就像这样,每个遵循 Alertable 的 UIViewController 都可以使用 issueAlert() 方法,甚至不必定义自己的实现。

        当然,我们也可以为 issueAlert 函数定义参数:

        extension Alertable where Self: UIViewController {
            func issueAlert(title: "Default Title", message: String = "Default Message") {
                // alert code here
            }
        }
        

        所以我们的视图控制器可以做到:

        issueAlert()
        

        issueAlert(title: "Error", message: "Something went wrong")
        

        我能想到的这种方法的两个优点是,您可以通过查看类定义中的 Alertable 协议来了解视图控制器是否可以访问此方法,并且各个视图控制器可以根据需要覆盖此方法提供自定义功能。当然,现在你也可以将 Alertable 合约指定为方法参数。

        【讨论】:

        • 我知道有点晚了,但没有。这很可能是最糟糕的方法,您发布的文章对于大型应用程序/系统是完全禁止的。在这种情况下,您期望开发人员现在将搜索所有视图控制器类并将Alertable 附加到它们并期望其他开发人员执行相同的操作,这是完全不可接受的。下一个问题是,一旦您实现自定义对话框,您将需要检查顶级控制器,例如 navigationController ?? self,它现在会破坏您的协议使用。最简单的是创建 UIViewController 扩展,最好的是 OP 所做的。
        • 我是 OP,只是在猜测其他解决方案。但是关于这个的想法。你能详细说明第二点(navigationController)吗?谢谢。
        • 当/如果您发现使用自定义对话框的最佳解决方案是将它们用作视图并将它们添加为视图(使用子视图控制器似乎效果最好)时,导航控制器部分就会成为问题。在我的情况下,我会调用viewController.attachDialog("message"),它在给定的视图控制器中显示对话框并且非常棒(也适用于分屏,因为它没有显示)。但是,如果我在导航控制器中执行此操作,则不会覆盖该栏。所以我需要打电话给viewController.navigationController?.attachDialog("message"),这会破坏通用工具...
        • 所以要像你一样使用它,我需要做两件事:首先我需要让我的导航控制器(每个导航控制器)对应于Alertable,我现在需要一个 GOD 类(或至少我认为没有更好的方法)所以我需要class MyNavigationController: UIViewController, Alertable。即便如此,我还需要打电话给什么? (navigationController as? Alertable ?? self).attachDialog("message")?它是零意义的。如果有的话,UIViewController 上的扩展就可以了,但调用 Alert.showIn(navigationController ?? self, message: "message") 会更好。
        【解决方案5】:

        来自 Sigex 的Answer 完全没问题,除了传递给跟踪按钮点击的int 索引可能没有意义,因为调用者需要跟踪 int 值。在这种情况下,传递字符串参数并在completion block 的 switch case 中比较它们对我来说更有意义。我宁愿用like,

        import UIKit
        
        extension UIViewController {
        
            func presentAlertWithTitle(title: String, message: String, options: String..., completion: @escaping (String) -> Void) {
                let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
                for (index, option) in options.enumerated() {
                    alertController.addAction(UIAlertAction.init(title: option, style: .default, handler: { (action) in
                        completion(options[index])
                    }))
                }
                self.present(alertController, animated: true, completion: nil)
            }
        }
        

        并测试,

        class TestViewController: UIViewController {
        
            override func viewDidLoad() {
                super.viewDidLoad()
        
                presentAlertWithTitle(title: "Test", message: "A sample message", options: "start", "stop", "cancel") { (option) in
                    print("option: \(option)")
                    switch(option) {
                        case "start":
                            print("start button pressed")
                            break
                        case "stop":
                            print("stop button pressed")
                            break
                        case "cancel":
                            print("cancel button pressed")
                            break
                        default:
                            break
                    }
                }
            }
        }
        

        【讨论】:

          【解决方案6】:

          为什么不创建一个将 AlertView 返回给 ViewController 的 Utility 函数?

          self.presentViewController(Utilities.createAlertController("errorMessage"), animated: true, completion: nil);
          

          【讨论】:

          • 我只是不喜欢在使用扩展名有意义时弄乱我的 Utils 文件。在这种情况下,也许它没有 100% 的意义,但我喜欢这样一个事实,即我所要做的就是从任何视图控制器中输入 alert("message") 并给出我的答案。
          • 还不错...我想这很方便
          【解决方案7】:

          为 swift 3 更新:

          如果您想在简单的代码行下方向用户显示警报消息;

          //函数定义:

          func showMessageToUser(title: String, msg: String)  {
              let alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.alert)
              alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
              self.present(alert, animated: true, completion: nil)
          }
          

          //函数调用:

          self.showMessageToUser(title: "Alert", msg: "your message to user")
          

          // 享受编码..!

          【讨论】:

            【解决方案8】:

            我在我的代码中使用了 Sigex 的扩展,但是我添加了一个检查,是否使用了选项。

            如果调用中没有给出任何选项,则警报仅显示“OK”并以返回选项 0 结束。

            extension UIViewController {
            
                func presentAlertWithTitle(title: String, message: String, options: String..., completion: @escaping (Int) -> Void) {
            
                    let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
                    if options.count == 0 {
                        let OKAction = UIAlertAction(title: "OK", style: .default, handler: { (action) in
                             completion(0)
                        })
                        alertController.addAction(OKAction)
                    } else {
            
                        for (index, option) in options.enumerated() {
                             alertController.addAction(UIAlertAction.init(title: option, style: .default, handler: { (action) in
                                completion(index)
                            }))
                        }
                    }
                    self.present(alertController, animated: true, completion: nil)
                }
            
            }
            

            只需省略, options: "1","2" 部分即可显示默认警报。

            【讨论】:

              【解决方案9】:

              我喜欢 Sigex 的扩展,但我根据标题为按钮添加了一些样式

              func presentAlertWithOptions(title: String, message: String, options: String..., completion: @escaping (Int) -> Void) {
                  let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
                  if options.count == 0 { //if there is no options, show a basic alert
                      let OKAction = UIAlertAction(title: "OK", style: .default, handler: { (action) in
                           completion(0)
                      })
                      alertController.addAction(OKAction)
                  } else { //alert with options
                      for (index, option) in options.enumerated() {
                          var alertStyle = UIAlertAction.Style.default
                          switch option { //check if we should style the buttons
                          case "Cancel": //cancel style
                              alertStyle = .cancel
                          case "Logout", "Discard Changes", "Discard", "Delete", "Remove": //destructive style
                              alertStyle = .destructive
                          default: break //keep as default
                          }
                          alertController.addAction(UIAlertAction(title: option, style: alertStyle, handler: { (action) in
                              completion(index)
                          }))
                      }
                  }
                  self.present(alertController, animated: true, completion: nil)
              }
              

              【讨论】:

                【解决方案10】:

                斯威夫特 4.1

                    let alert = UIAlertController(title: "Atenção",message: "Mensagem Aqui",preferredStyle: .alert)
                
                    alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
                    self.present(alert, animated: true)
                

                【讨论】:

                  猜你喜欢
                  • 2018-03-03
                  • 1970-01-01
                  • 2021-08-19
                  • 1970-01-01
                  • 2020-09-25
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-09-29
                  相关资源
                  最近更新 更多