10
votes

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.

2
Are you sure, that the rootViewController on which you're trying to present UIAlertController is visible and not covered by another modal view controller for example? - dive
Push the debug views button (its in the bar over the debug console) on this viewController. On the left hand side you will see your entire view stack with the Window at the top. You can right click on any view to print a description. Compare this to the view of rootViewController(); it has to be the case that show how your rootViewController's view is no longer in the hierarchy. Pick a view that is and use that instead. - Josh Homann
Any solution found? Encountering same problem. - Rohan Sanap

2 Answers

27
votes

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

3
votes

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.