通过外部静态函数在ViewController上显示提醒

时间:2018-07-26 18:36:24

标签: ios swift uiviewcontroller uialertcontroller

我有一个注册视图控制器,它调用Service类并使用其static func signUp(...)来将某人注册到数据库。

如果注册失败,则应通过showAlert(...)静态方法显示警报。

但是,正在发生的情况是未成功注册,但是没有使用我当前的方法显示警报。

Attempt to present <UIAlertController: xx> on <Yyy:SignUpViewController: ss> whose view is not in the window hierarchy!

当前,我正在尝试将SignUpViewController作为参数(vc: UIViewController)传递给静态方法,然后调用Service.showAlert(on: vc, ...)

我还尝试将showAlert(...)类中的SignUpViewController方法合并为extension UIViewController,并从Service signUp()调用为vc.showAlert(...) 。我收到与上述相同的错误。

重要的是,我想将代码重用于来自不同View Controller的数据库调用,所以我不想重写代码并将其放在每个View Controller中。这不仅是为了注册。我希望在外部类中进行这些数据库调用。

代码:

服务等级

static func signUp(email: String, password: String, vc: UIViewController) {
        Auth.auth().signIn(withEmail: email, password: password) { (authResult, error) in
            if let error = error {
                print("Failed to sign in with error ", error)
                Service.showAlert(on: vc, style: .alert, title: "Sign-in Error", message: error.localizedDescription)
                return
            }
            // ...code
        }
        // ...code
}

// other methods

static func showAlert(on: UIViewController, style: UIAlertControllerStyle, title: String?, message: String?, actions: [UIAlertAction] = [UIAlertAction(title: "Ok", style: .default, handler: nil)], completion: (() -> Swift.Void)? = nil) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: style)
        for action in actions {
            alert.addAction(action)
        }
        on.present(alert, animated: true, completion: completion)
}

SignUpViewController类方法调用

Service.signUp(email: emailTextField.text!, password: passwordTextField.text!, vc: self)

编辑:

如果我在SignUpViewController中执行登录功能,则会显示警报:

@IBAction func btnActionLogin(_ sender: Any) {
                    Auth.auth().createUser(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!) { (authResult, error) in
                        if let error = error {
                            print("Failed to create new user with error ", error)
                            Service.showAlert(on: self, style: .alert, title: "Account Creation Error", message: error.localizedDescription)
                            return
                        } else {
                        // ... more code
                    }

}

编辑2:

我实施的方法实际上很好。这是我在错误的位置执行切换视图控制器的操作!我不小心切换了View Controller,这表示登录成功,即使登录失败也是如此。

1 个答案:

答案 0 :(得分:1)

如果不查看Auth文档,就不能100%确定解决方案,但是我想函数Auth.auth().signIn(withEmail: email, password: password)是在后台线程上执行的。

由于您正在从此后台线程调用Attempt to present <UIAlertController: xx> on <Yyy:SignUpViewController: ss> whose view is not in the window hierarchy!,可能导致错误Service.showAlert(on: vc, style: .alert, title: "Sign-in Error", message: error.localizedDescription)。当后台线程执行命令向用户显示警报时,视图很可能不再位于堆栈上。

运行任何会影响主线程上的UI的代码很重要。

我建议您通过用DispatchQueue.main.async包装该行代码,从而在主线程上异步执行代码,如下所示:

DispatchQueue.main.async { Service.showAlert(on: vc, style: .alert, title: "Sign-in Error", message: error.localizedDescription) }

希望这可以解决问题。如果没有报告,我会尽力考虑其他情况。

更新:要回答有关显示警报的正确方法的问题:

  

”当前,我正在尝试将SignUpViewController作为   参数(vc:UIViewController)到静态方法,然后调用   Service.showAlert(on:vc,...)。我不认为这是正确的   方法。”

我使用相同的方法来调用静态方法。我认为这种范例没有问题。我通常在项目中执行此操作的方式如下:

我创建了一个与您类似的静态方法,用于在视图控制器上显示警报。

/** Easily Create, Customize, and Present an UIAlertController on a UIViewController

 - Parameters:
    - target: The instance of a UIViewController that you would like to present tye UIAlertController upon.
    - title: The `title` for the UIAlertController.
    - message: Optional `message` field for the UIAlertController. nil by default
    - style: The `preferredStyle` for the UIAlertController. UIAlertControllerStyle.alert by default
    - actionList: A list of `UIAlertAction`. If no action is added, `[UIAlertAction(title: "OK", style: .default, handler: nil)]` will be added.

 */
func showAlert(target: UIViewController, title: String, message: String? = nil, style: UIAlertControllerStyle = .alert, actionList:[UIAlertAction] = [UIAlertAction(title: "OK", style: .default, handler: nil)] ) {
    let alert = UIAlertController(title: title, message: message, preferredStyle: style)
    for action in actionList {
        alert.addAction(action)
    }
    // Check to see if the target viewController current is currently presenting a ViewController
    if target.presentedViewController == nil {
        target.present(alert, animated: true, completion: nil)
    }
}

然后我从视图控制器中调用函数,如下所示:showAlert(target: self, title: "Error", message: "Some error message")