Hi,
I have a ViewController that presents another ViewController as a modal over full screen when a button is touched.
let vc = UIStoryboard(name: "XXX", bundle: nil).instantiateViewController(withIdentifier: "OverFullScreenModalViewController") as! OverFullScreenModalViewController
vc.modalPresentationStyle = .overFullScreen
vc.modalTransitionStyle = .crossDissolve
self.present(vc, animated: true, completion: nil)
Then, on my modal ViewController I have a button that, when touched, I want to present a confirmation alert
@IBAction func handleDelete(_ sender: Any) {
let negativeHandler:((Any) -> ()) = {(_) in
//do nothing
}
let handler:((Any) -> ()) = {(_) in
// Delete
}
DispatchQueue.main.async {
let alert = UIAlertController(title: "Please confirm", message: "Are you sure?", preferredStyle: .alert)
let positiveAction = UIAlertAction(title: "yes", style: .default, handler: handler)
alert.addAction(UIAlertAction(title: "no", style: .cancel, handler: negativeHandler))
alert.addAction(positiveAction)
alert.preferredAction = positiveAction
self.present(alert, animated: true)
}
}
But what happens is that the modal is dismissed and I get this error on the console:
[Presentation] Attempt to present <UIAlertController: 0x7ff78d37cc00> on <OverFullScreenModalViewController: 0x7ff792814200> (from <OverFullScreenModalViewController: 0x7ff792814200>) whose view is not in the window hierarchy.
I've tried with and without DispatchQueue.main.async, nothing is trying to be presented on viewDidLoad, viewWillAppear or viewDidAppear
Any ideas?
You should make sure that alert is presented from its view hierarchy.
So, find the topMost VC in its hierarchy
func getTopMostViewController() -> UIViewController? {
var topMostViewController = UIApplication.shared.keyWindow?.rootViewController
while let presentedViewController = topMostViewController?.presentedViewController {
topMostViewController = presentedViewController
}
return topMostViewController
}
And present from it:
getTopMostViewController()?.present(alert, animated: true, completion: nil)
Note: as keyWindow is now deprecated, you may have to replace
var topMostViewController = UIApplication.shared.keyWindow?.rootViewController
by:
var topMostViewController = UIApplication.shared.windows[0].rootViewController
or
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
guard let window = windowScene?.windows.first else { return nil }
var topMostViewController = window.rootViewController