尝试呈现其视图不在 Windows 层次结构中的 ViewController

Posted

技术标签:

【中文标题】尝试呈现其视图不在 Windows 层次结构中的 ViewController【英文标题】:Attempt to present ViewController whose view is not in the windows hierarchy 【发布时间】:2016-10-28 11:46:47 【问题描述】:

我遇到了一个奇怪的问题:我制作了 2 个视图控制器,我可以用代码切换视图:

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)


我的应用程序正确打开到第一个视图控制器,然后,当我单击在精灵套件场景上创建的按钮时,我可以成功地将视图切换到我的新视图控制器(我的第二个场景成功显示)但是然后,在此切换后我无法再更改我的视图控制器。如果我再次单击该按钮,我会收到以下消息:

尝试在 Test_Vuforia.GameViewController: 0x12f549610 上呈现,其视图不在窗口层次结构中!

你知道是什么问题吗?我知道我处于根位置,因此在切换视图控制器后我无法再更改它,但是如何更改呢?

谢谢!

编辑:

我的代码在 SKScene 内部使用,而不是来自 UIVewController,当我使用后缀 self. : View (SKScene) 类型的值没有“存在”成员。

我正在使用 Vuforia 创建增强现实游戏,我需要使用 SKScene 切换 AR 视图。

【问题讨论】:

【参考方案1】:

问题

当前 viewController 不是来自 UIApplicationrootViewController。所以你应该找到当前可见的 viewController,然后从那里呈现出来。

解决方案

只需在您的 UIApplication Stack 上找到 topViewController,然后从那里展示您的控制器。

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

UIApplication 的这个扩展对您的情况非常有用

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
    

参考:Gist

【讨论】:

您的解决方案有效,谢谢!唯一的问题是我的 iPad Air 2 在 ViewController 演示 3 个周期后变得非常慢(几乎冻结)。RAM 使用量增长到 90 MB,这对于 Ipad Air 2 来说并不是那么多,你知道为什么会发生这种情况吗?也许有必要清理和删除旧的已查看视图控制器? 这取决于你在那里做什么。如果一段时间后您不再需要presentedControllers,您可以将rootViewController更改为您需要展示的那个。【参考方案2】:

viewDidAppear 中的调用函数对我有帮助。 Swift 3 的解决方案:

在您的主控制器中:

override func viewDidAppear(_ animated: Bool) 
    super.viewDidAppear(animated)

    showTutorialModally()


func showTutorialModally() 
    let tutorialViewController = TutorialViewController()
    tutorialViewController.modalPresentationStyle = .overCurrentContext
    present(tutorialViewController, animated: true, completion: nil)

在您的教程控制器中:

view.backgroundColor = UIColor.clear
view.isOpaque = false

【讨论】:

【参考方案3】:

使用下面的扩展来检索堆栈中的下一个可用控制器。

Swift 3

extension UIResponder 
    func next<T: UIResponder>(_ type: T.Type) -> T? 
        return next as? T ?? next?.next(type)
    

Swift 2.3

extension UIResponder 
    func nextResponder<T: UIResponder>(_ type: T.Type) -> T? 
        return nextResponder() as? T ?? nextResponder()?.nextResponder(type)
    

在您的SKScene 中,view?.next(UIViewController.self) 为您提供层次结构中下一个可用的UIViewController

将此扩展添加到项目中名为 Categories 的组中,如果该组不存在,请创建它,然后创建一个名为 UIResponder+NextOfType.swift 的新文件并粘贴扩展。

【讨论】:

我得到一个错误“当我使用时无法调用非函数类型'UIResponder'的值:next(UIViewController.self)?.present(ViewControllernew1, animated: true, completion: nil)跨度> 你用的是swift 3吗? 支持 XCode 8 和 Sierra 这是我的代码: let newViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "viewController3") next(UIViewController.self)?.present(newViewController , animated :真,完成:无) 好的,如果您使用我更新的答案中的扩展名更新扩展名,这将起作用【参考方案4】:

Xcode 错误意义大致为:此视图不在视图层次结构的 Window 中。

我不认为以上回答问题,但也许您可能想知道为什么会发生这种情况。

但是我发现你这个问题的原因很可能是在ViewController生命周期中ViewDidLoading切换视图代码执行里面。

原因大概是,当ViewController在初始化时执行allco init时,会异步执行viewWillLoad -> viewDidLoad... -- -- -- --> viewDidApper。然后可能是在代码执行到viewDidLoad。 ViewController 可能不会为 Window 分配值。根视图控制器。所以我们直接使用[self presentViewController:]会出现这个错误。

建议你把switch的代码移到ViewDidApper中。

希望对你有帮助。

【讨论】:

【参考方案5】:

    您的rootViewController 可能不是当前的ViewController。您在其上展示或推送了一个新的 UIViewController。

    viewController's 视图不在 窗口在加载时的视图层次结构(当 viewDidLoad 消息已发送),但它在窗口中 呈现后的层次结构(当viewDidAppear: 消息已发送)。 如果您从以下位置调用 showController 方法 viewDidLoad 只需从 viewDidAppear 方法调用它

执行以下操作:

 let vc: UIViewController = (self.storyboard?.instantiateViewControllerWithIdentifier("viewController2"))!
 self.presentViewController(vc, animated: true, completion: nil)

 // OR
 self.navigationController?.pushViewController(vc, animated: true)

【讨论】:

【参考方案6】:

这样使用

let vc = self.view?.window?.rootViewController
func showController()

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

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

也许问题出在 currentViewController 上。

【讨论】:

问题是我在 SKScene 中使用此代码,而 self.present(ViewControllernew1, animated: true, completion: nil) 不起作用,我收到此错误:View (SKScene) 类型的值有没有成员“在场”。

以上是关于尝试呈现其视图不在 Windows 层次结构中的 ViewController的主要内容,如果未能解决你的问题,请参考以下文章

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

尝试呈现其视图不在视图层次结构中的 UITabBarController - Firebase,Swift

尝试呈现其视图不在窗口层次结构中的 UIAlertController (Swift 3/Xcode 8)