【问题标题】:Attempt to present ViewController whose view is not in the windows hierarchy尝试呈现其视图不在 Windows 层次结构中的 ViewController
【发布时间】: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 视图。

【问题讨论】:

    标签: ios swift


    【解决方案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】:
        1. 您的rootViewController 可能不是当前的ViewController。您在其上展示或推送了一个新的 UIViewController。

        2. 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) 类型的值有没有成员“在场”。
          猜你喜欢
          • 2015-09-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-25
          • 2013-02-23
          • 2019-06-10
          • 2014-06-01
          • 1970-01-01
          相关资源
          最近更新 更多