Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS. Attempt to present UIAlertController on UIViewController whose view is not in the window hierarchy

Swift 3, Xcode 8.1. I want to display UIAlertController in UIViewController.

I have methods:

private static func rootViewController() -> UIViewController {
    // cheating, I know

    return UIApplication.shared.keyWindow!.rootViewController!
}

static func presentAlert(_ message: String) {
    let alertView = UIAlertController(title: "RxExample", message: message, preferredStyle: .alert)
    alertView.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in })

    rootViewController().present(alertView, animated: true, completion: nil)
}

Full code of this class you can find here

I call the method presentAlert in viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    DefaultWireframe.presentAlert("test")
    ...
}

and got the warning:

Warning: Attempt to present UIAlertController: 0x7f904ac0d930 on UIViewController: 0x7f904ad08040 whose view is not in the window hierarchy!

How to avoid the warning and display the Alert?

It works when I try to show Alert in initial ViewController, but it doesn't work in another ViewController connected using push segue with initial VC.

like image 830
Igor Kasuan Avatar asked Nov 17 '16 22:11

Igor Kasuan


2 Answers

In viewDidLoad, your app has not presented the view controller to the user yet, so an alert cannot be shown. Try executing that code in viewDidAppear

like image 66
karnett Avatar answered Nov 19 '22 03:11

karnett


I had similar problem/case where action sheet was not showing on a ViewController which was pushed on another ViewController. The error it was giving was also similar as your's. What you have done works perfectly on normal ViewControllers but just doesn't work on the ViewControllers which are pushed over other ViewController.

I solved the problem by making the object of class UIAlertController as an instance variable of my class rather than keeping it local inside the triggering function.

So in your case, try declaring var alertView: UIAlertController? at top of the class where instance variables are declared and then just initialise it in your desired triggering function to use it like this:

static func presentAlert(_ message: String) {
    self.alertView = UIAlertController(title: "RxExample", message: message, preferredStyle: .alert)
    alertView.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in })

    rootViewController().present(alertView, animated: true, completion: nil)
}

Might be some bug from Apple's side in maintaining reference which was causing this problem. But work around I wrote above works perfect.

like image 4
Rohan Sanap Avatar answered Nov 19 '22 04:11

Rohan Sanap