【问题标题】:Warning: Attempt to present * on * whose view is not in the window hierarchy - swift警告:尝试在其视图不在窗口层次结构中的 * 上呈现 * - swift
【发布时间】:2014-11-19 07:01:03
【问题描述】:

我正在尝试提供ViewController如果数据模型中有任何保存的数据。但我收到以下错误:

警告:尝试在其视图不在窗口层次结构中的 * 上呈现 *"

相关代码:

override func viewDidLoad() {
    super.viewDidLoad()
    loginButton.backgroundColor = UIColor.orangeColor()

    var request = NSFetchRequest(entityName: "UserData")
    request.returnsObjectsAsFaults = false

    var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
    var context:NSManagedObjectContext = appDel.managedObjectContext!

    var results:NSArray = context.executeFetchRequest(request, error: nil)!

    if(results.count <= 0){
        print("Inga resultat")
    } else {
        print("SWITCH VIEW PLOX")
        let internVC = self.storyboard?.instantiateViewControllerWithIdentifier("internVC") as internViewController
        self.presentViewController(internVC, animated: true, completion: nil)
    }
}

我尝试了使用 Google 找到的不同解决方案,但均未成功。

【问题讨论】:

  • 你在 Storyboard 中连接你的 ViewController 了吗?你在这里使用 NavigationController 吗?
  • 如果我在 Storyboard 中连接了我的 ViewController,这对你意味着什么?我没有使用NavigationController@derdida
  • 尝试:ViewDidLoad中的self.addChildViewController(childController: UIViewController)
  • 这会产生错误。它需要在“类型名称”(UIViewController 部分)之后调用成员名称或构造函数。 @derdida
  • 你在哪里写的?在 MainViewController 的 ViewDidLoad 中?

标签: ios swift hierarchy presentviewcontroller


【解决方案1】:

使用主线程呈现和关闭视图控制器对我有用。

DispatchQueue.main.async { self.present(viewController, animated: true, completion: nil) }

【讨论】:

    【解决方案2】:

    Swift 5.1

    let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
    let mainViewController = storyboard.instantiateViewController(withIdentifier: "ID")
    let appDeleg = UIApplication.shared.delegate as! AppDelegate
    let root = appDeleg.window?.rootViewController as! UINavigationController
    root.pushViewController(mainViewController, animated: true)
    

    【讨论】:

      【解决方案3】:

      Swift 方法,并提供演示。

      func topMostController() -> UIViewController {
          var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
          while (topController.presentedViewController != nil) {
              topController = topController.presentedViewController!
          }
          return topController
      }
      
      func demo() {
          let vc = ViewController()
          let nav = UINavigationController.init(rootViewController: vc)
          topMostController().present(nav, animated: true, completion: nil)
      }
      

      【讨论】:

        【解决方案4】:

        前面的答案与应该呈现视图的视图控制器 1) 尚未添加到视图层次结构中,或 2) 不是顶部视图控制器的情况有关。
        另一种可能性是,应该在另一个警报已经出现但尚未解除的同时显示一个警报。

        【讨论】:

          【解决方案5】:

          我在用户打开深层链接后呈现控制器时收到此错误。 我知道这不是最好的解决方案,但如果您在短时间内可以快速解决 - 只需将您的代码包装在 asyncAfter:

          DispatchQueue.main.asyncAfter(deadline: .now() + 0.7, execute: { [weak self] in
                                          navigationController.present(signInCoordinator.baseController, animated: animated, completion: completion)
                                      })
          

          您的演示控制器将有时间致电viewDidAppear

          【讨论】:

            【解决方案6】:

            您只需要延迟执行选择器 - (0 秒有效)。

            override func viewDidLoad() {
                super.viewDidLoad()
                perform(#selector(presentExampleController), with: nil, afterDelay: 0)
            }
            
            @objc private func presentExampleController() {
                let exampleStoryboard = UIStoryboard(named: "example", bundle: nil)
                let exampleVC = storyboard.instantiateViewController(withIdentifier: "ExampleVC") as! ExampleVC
                present(exampleVC, animated: true) 
            }
            

            【讨论】:

            • 非常感谢。我被这个问题困了一个多小时。
            • 谢谢... @objc func presentExampleController()
            • 我认为这是一个了不起的答案!
            • 这是一个 hack(现在可能有效),但会让您在意外情况下遇到问题。
            【解决方案7】:

            不用找顶视图控制器,可以使用

            viewController.modalPresentationStyle = UIModalPresentationStyle.currentContext
            

            其中 viewController 是您要呈现的控制器 这在层次结构中有不同类型的视图(如 TabBar、NavBar)时很有用,尽管其他视图似乎是正确的,但更像是 hackish

            其他演示风格可以在apple doc找到

            【讨论】:

              【解决方案8】:

              当您有UINavigationControllerUITabBarController 时,这里所有topViewController 的实现都不是完全支持的情况,对于这两种情况,您需要稍微不同的处理方式:

              对于UITabBarControllerUINavigationController,您需要不同的实现。

              这是我用来获取 topMostViewController 的代码:

              protocol TopUIViewController {
                  func topUIViewController() -> UIViewController?
              }
              
              extension UIWindow : TopUIViewController {
                  func topUIViewController() -> UIViewController? {
                      if let rootViewController = self.rootViewController {
                          return self.recursiveTopUIViewController(from: rootViewController)
                      }
              
                      return nil
                  }
              
                  private func recursiveTopUIViewController(from: UIViewController?) -> UIViewController? {
                      if let topVC = from?.topUIViewController() { return recursiveTopUIViewController(from: topVC) ?? from }
                      return from
                  }
              }
              
              extension UIViewController : TopUIViewController {
                  @objc open func topUIViewController() -> UIViewController? {
                      return self.presentedViewController
                  }
              }
              
              extension UINavigationController {
                  override open func topUIViewController() -> UIViewController? {
                      return self.visibleViewController
                  }
              }
              
              extension UITabBarController {
                  override open func topUIViewController() -> UIViewController? {
                      return self.selectedViewController ?? presentedViewController
                  }
              }
              

              【讨论】:

                【解决方案9】:

                斯威夫特 4

                func topMostController() -> UIViewController {
                    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
                    while (topController.presentedViewController != nil) {
                        topController = topController.presentedViewController!
                    }
                    return topController
                }
                

                【讨论】:

                • 解释和示例会很有帮助@AllenWixted
                【解决方案10】:

                我尝试了很多方法!唯一有用的是:

                if var topController = UIApplication.shared.keyWindow?.rootViewController
                {
                  while (topController.presentedViewController != nil)
                  {
                    topController = topController.presentedViewController!
                  }
                }
                

                【讨论】:

                  【解决方案11】:

                  此时,在您的代码中,仅创建了视图控制器的视图,但未将其添加到任何视图层次结构中。如果您想尽快从该视图控制器呈现,您应该在viewDidAppear 中进行,以确保最安全。

                  【讨论】:

                  • 如果我把它放在viewDidAppear中,那么当我关闭presentedViewController时,它会再次调用viewDidAppear方法并再次呈现viewController。我有一个在呈现之前放置条件语句的解决方法,但是有什么办法可以代替条件语句?
                  • 我会说,当屏幕出现时尝试呈现另一个模式是一种奇怪的行为,所以状态布尔并不是最糟糕的解决方案。同时,想想您需要显示模式的根本原因,看看您是否可以访问该信息。
                  • 如果在viewWillAppear中进行,开始演示时会出现正在演示中的情况。另一种方法是将其放在 viewWillAppear 中,但使用 iOS 8 中的新transitionCoordinator 属性在过渡完成中添加代码。更多信息可以在这里找到developer.apple.com/library/prerelease/ios/documentation/UIKit/…
                  【解决方案12】:

                  斯威夫特 3.

                  调用此函数以获取最顶层的视图控制器,然后让该视图控制器出现。

                  func topMostController() -> UIViewController {
                      var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
                          while (topController.presentedViewController != nil) {
                              topController = topController.presentedViewController!
                          }
                          return topController
                      }
                  

                  用法:

                  let topVC = topMostController()
                  let vcToPresent = self.storyboard!.instantiateViewController(withIdentifier: "YourVCStoryboardID") as! YourViewController
                  topVC.present(vcToPresent, animated: true, completion: nil)
                  

                  【讨论】:

                  • 感谢@Jacob Davis!我用它来展示 alertController 因为我收到了警告:尝试展示......
                  • 这非常有用。一些正在呈现控制器但屏幕没有出现的东西。突然它被解雇了。还有其他代码需要实现吗?请建议
                  【解决方案13】:

                  适用于 swift 3.0 及以上版本

                  public static func getTopViewController() -> UIViewController?{
                  if var topController = UIApplication.shared.keyWindow?.rootViewController
                  {
                    while (topController.presentedViewController != nil)
                    {
                      topController = topController.presentedViewController!
                    }
                    return topController
                  }
                  return nil}
                  

                  【讨论】:

                    【解决方案14】:

                    斯威夫特 3

                    作为一个新手,我不断出现这种情况,发现当前加载的模式视图可以被关闭,但如果您不需要显示模式,最好切换到根控制器。

                    我在用这个

                    let storyboard = UIStoryboard(name: "Main", bundle: nil)
                    let vc  = storyboard?.instantiateViewController(withIdentifier: "MainAppStoryboard") as! TabbarController
                    present(vc, animated: false, completion: nil)
                    

                    将它与我的 tabController 一起使用:

                    let storyboard = UIStoryboard(name: "Main", bundle: nil)
                    let view = storyboard.instantiateViewController(withIdentifier: "MainAppStoryboard") as UIViewController
                    let appDelegate = UIApplication.shared.delegate as! AppDelegate
                    //show window
                    appDelegate.window?.rootViewController = view
                    

                    如果您需要在多个故事板屏幕之间切换,只需调整为视图控制器即可。

                    【讨论】:

                      【解决方案15】:
                      let storyboard = UIStoryboard(name: "test", bundle: nil)
                      let vc = storyboard.instantiateViewController(withIdentifier: "teststoryboard") as UIViewController
                      UIApplication.shared.keyWindow?.rootViewController?.present(vc, animated: true, completion: nil)
                      

                      这似乎可以确保它是最顶部的视图。

                      我遇到了一个错误

                      警告:尝试在其视图不在窗口层次结构中的 myapp.testController: 0x7fdd01703690 上呈现 myapp.testController: 0x7fdd01703990!

                      希望这可以帮助其他人使用 swift 3

                      【讨论】:

                        【解决方案16】:

                        对于 SWIFT

                        func topMostController() -> UIViewController {
                            var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
                            while (topController.presentedViewController != nil) {
                                topController = topController.presentedViewController!
                            }
                            return topController
                        }
                        

                        【讨论】:

                        • 谢谢!这是为我解决此错误的唯一方法。我试图在视图完全加载之后(在 Xcode 8 / iOS 10 中)从手势识别器触发的函数中呈现模态 VC。奇怪的是,这个函数返回的topControllerself在尝试直接使用self.presentViewController(myModalVC)呈现时完全相同的VC,但是当我使用你的函数传入呈现的VC时没有视图层次错误。跨度>
                        【解决方案17】:

                        在目标 c 中: 这解决了我在 mpmovieplayer 上展示 viewcontroller 时遇到的问题

                        - (UIViewController*) topMostController
                        {
                            UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
                        
                            while (topController.presentedViewController) {
                                topController = topController.presentedViewController;
                            }
                        
                            return topController;
                        }
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 2015-11-16
                          • 2020-08-07
                          • 1970-01-01
                          • 1970-01-01
                          • 2013-02-23
                          • 2017-07-18
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多