尝试呈现其视图不在 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 不是来自 UIApplication
的 rootViewController
。所以你应该找到当前可见的 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