Swift 4 尝试显示视图不在 window 层次结构中的 ViewController

Swift 4 Attempt to present ViewController whose view is not in the window hierarchy

我正在使用 swift 4 并尝试创建 alertView,但在使用 Firebase 注册用户时出现错误。我有一个 IBAction 用于注册按钮,它将使用来自两个 textfields 的文本对用户进行注册,一个用于电子邮件,一个用于密码。

我基本上是在注册过程出现错误时尝试显示 alertview,例如 textfield.

为空

我已将函数的屏幕截图附加到发生的位置。我知道我实际上遇到了一个错误,因为如果有错误,print 语句会输出一个错误。

无论是否有错误,都不会显示警报视图,并且应用程序会执行 segue。

2019-01-15 21:40:26.368924-0500 Pronto[9036:225268] Warning: Attempt to present on whose view is not in the window hierarchy

这是我为现在显示的警报视图获得的输出。 我查看了所有其他关于同一问题的帖子,但 none 似乎有效。

您可以获得最顶层的视图控制器并让该视图控制器显示警报。因此,不要使用 self.present,而是使用这种方法,看看它是否有效:

let topViewController = UIApplication.shared.keyWindow?.rootViewController
topViewController?.present(alertController, animated: true, completion: nil)

也尝试在主线程上呈现,因为您正试图在 createUser 完成处理程序中显示警报:

DispatchQueue.main.async { 
    self.present(alertController, animated: true, completion: nil)
}

检查您是否有 "double tap" 问题:

  1. 您不小心双击了按钮
  2. signUpBtnPressed 被调用了两次
  3. 第一个请求正确执行,从而启动segue,错误为nil
  4. 第二个请求 returns 错误 'user already exists',然后尝试显示来自当前控制器的警报,但是 segue 已经启动并且下一个控制器已经出现

这已通过使用带 UI 阻塞的加载器解决(例如 SVProgressHUD)- 在方法开始时启动加载器并在回调中关闭它。

尝试使用 ViewDidAppear 而不是 View 来加载。

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    let alertViewController = UIAlertController(title: "Any", message: "Any Custom Message", preferredStyle: .alert)

    alertController.addAction(UIAlertAction(title: "ANy", style: .cancel, handler: nil))
    present(alertViewController, animated: true, completion: nil)
}

此问题是由于您的视图层次结构所致。

You need to find out what is your Current/Topmost view controller in view hierarchy and present your alert over it.

要找出最顶层的视图控制器,请使用以下代码:

func getTopMostViewController() -> UIViewController? {
    var topMostViewController = UIApplication.shared.keyWindow?.rootViewController

    while let presentedViewController = topMostViewController?.presentedViewController {
        topMostViewController = presentedViewController
    }

    return topMostViewController
}

并在最顶层的视图控制器上显示您的警报并使用主线程显示警报,因为闭包可能在另一个线程上工作。

DispatchQueue.main.async { 
    getTopMostViewController()?.present(alertController, animated: true, completion: nil)
}

请参考堆栈答案: