Attempt to Present Uiviewcontroller on Uiviewcontroller Whose View Is Not in the Window Hierarchy

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

Where are you calling this method from? I had an issue where I was attempting to present a modal view controller within the viewDidLoad method. The solution for me was to move this call to the viewDidAppear: method.

My presumption is that the view controller's view is not in the window's view hierarchy at the point that it has been loaded (when the viewDidLoad message is sent), but it is in the window hierarchy after it has been presented (when the viewDidAppear: message is sent).


Caution

If you do make a call to presentViewController:animated:completion: in the viewDidAppear: you may run into an issue whereby the modal view controller is always being presented whenever the view controller's view appears (which makes sense!) and so the modal view controller being presented will never go away...

Maybe this isn't the best place to present the modal view controller, or perhaps some additional state needs to be kept which allows the presenting view controller to decide whether or not it should present the modal view controller immediately.

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

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

Attempt to present ViewController whose view is not in the windows hierarchy

Issue

Current viewController is not the rootViewController from UIApplication. So you should find the current viewController which is visible and then present it from there.

Solution

Simply find the topViewController on your UIApplication Stack, and from there present your controller.

let newViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "viewController2")
UIApplication.topViewController()?.present(newViewController, animated: true, completion: nil)

This extension of UIApplication comes in handy for your case

extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}

References: Gist

Attempt to present vc whose view is not in the window hierarchy

Add extention given bellow to your application and use it any where you want to present any view controller, it works for me hope it helps you.

//MARK: - UIApplication Extension
extension UIApplication {
class func topViewController(viewController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = viewController as? UINavigationController {
return topViewController(viewController: nav.visibleViewController)
}
if let tab = viewController as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(viewController: selected)
}
}
if let presented = viewController?.presentedViewController {
return topViewController(viewController: presented)
}
return viewController
}
}

And Present it by following code:

 UIApplication.topViewController()?.present(vc, animated: true, completion: nil)

presenting whose view is not in the window hierarchy warning

Your LoginVC is perfectly fine.

However, you need to change your HomeVC as @Sh_Khan suggested and move the testing code from viewDidLoad to viewDidAppear:

import UIKit
import Firebase

class HomeVC: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
}

// HomeVC.view was added to a view hierarchy
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

// to check whether the user has already logged in or not
Auth.auth().addStateDidChangeListener { (auth, user) in
if user == nil {
let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
self.present(login, animated: true, completion: nil)
}
}
}
}

Explanation

Your viewDidLoad method gets called before the viewController gets presented, so it at that moment it cannot really present another view controller (since it itself is not presented), viewDidLoad documentation:

Called after the controller's view is loaded into memory.

This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView() method. You usually override this method to perform additional initialization on views that were loaded from nib files.

In that moment the viewController is not in the window hierarchy yet.

viewDidAppear however gets called when the view is presented and becomes a part of the window hierarchy, viewDidAppear documentation:

Notifies the view controller that its view was added to a view hierarchy.

You can override this method to perform additional tasks associated with presenting the view. If you override this method, you must call super at some point in your implementation.

Don't forget to call super.viewDidAppear during overriding it.

I got this warning attempt to present ViewController whose view is not in the window hierarchy when I try to present a view

If you want to show VC1 from VC3 the you not need to present it again because it is already loaded in navigation stack. you just need to dismiss or pop VC3 and VC2 from navigation stack. If you have presented it then dismiss and if you have pushed it then popped it.

Your warning's meaning : you are trying to presenting which is in the view hierarchy of navigation controller 1 but not in the view hierarchy of navigation controller 2.!!

Hope this will help :)

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

I have resolved the issue the main problem is exactly what it says the view is not in the view hierarchy. In order to resolve this issue we need to set the root view controller to the current view controller using the appDelegate object. So that the view now comes in the view hierarchy and be able to present further views. Here is the code

let initialViewController = UIStoryboard(name: "Main", bundle:nil).instantiateInitialViewController() as UIViewController
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
appDelegate.window?.rootViewController = initialViewController

Please read this for further information. https://stackoverflow.com/a/27608804/5123516



Related Topics



Leave a reply



Submit