Pierro787 Pierro787 - 1 month ago 9
Swift Question

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

I meet a strange problem: I made 2 view controllers for wich I can switch the view with code:

var currentViewController:UIViewController=UIApplication.shared.keyWindow!.rootViewController!

func showController()
{
let ViewControllernew1 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "viewController2")

currentViewController.present(ViewControllernew1, animated: true, completion: nil)

}


My app open correctly to the first view controller, then, when I click on the button created on a sprite kit scene, I can switch the view to my new view controller successfully (I get my second scene successfully showed) but then, I can not change anymore my view controller after this switch. If I click again on the button, I get this message:

Attempt to present on Test_Vuforia.GameViewController: 0x12f549610 whose view is not in the window hierarchy!

Do you know what is the problem ? I understand I'm in the root position so that I can not change anymore my view controller after having switched it, but how to change that ?

Thanks !

Edit:

My code is used inside a SKScene and not from a UIVewController and I get this error when I use the suffix self. : Value of type View (SKScene) has no member 'present'.

I'm creating an augmented reality game with Vuforia and I need to switch AR view with SKScene.

Answer

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.sharedApplication().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: Zammbi