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

帅比萌擦擦* 提交于 2019-12-03 20:08:07

This issue happens due to your view hierarchy.

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

To find out topmost view controller use following code:

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

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

    return topMostViewController
}

And present your alert over topmost view controller and use main thread to present an alert because closures may have working on another thread.

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

Please refer to this stack answer: Swift 3 Attempt to present whose view is not in the window hierarchy

Mayank Wadhwa

Try using ViewDidAppear instead of View did Load.

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 can get the top most view controller and have that view controller present the alert. So instead of self.present use this approach and see if it works:

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

Also try presenting on the main thread, since you're trying to show the alert in createUser completion handler:

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

Check if you have "double tap" issue:

  1. You double tap button accidentally
  2. signUpBtnPressed is called twice
  3. First request is executed correctly, thus launching the segue, and the error is nil
  4. Second request returns error like 'user already exists', then trying to show alert from current controller, but segue is already launched and next controller is already presented

This is fixed by using loader with UI blocking (for example SVProgressHUD) - start loader at the beginning of the method and dismiss it in callback.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!