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

Kyl*_*lan 573 cocoa-touch views hierarchy ios ios6

刚开始使用Xcode 4.5,我在控制台中遇到了这个错误:

警告:尝试在<ViewController:0x1ec3e000>上显示<finishViewController:0x1e56e0a0>,其视图不在窗口层次结构中!

该视图仍在呈现中,应用程序中的所有内容都正常运行.这是iOS 6中的新功能吗?

这是我用来在视图之间切换的代码:

UIStoryboard *storyboard = self.storyboard;
finishViewController *finished = 
[storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];

[self presentViewController:finished animated:NO completion:NULL];
Run Code Online (Sandbox Code Playgroud)

Jam*_*ord 1246

你在哪里叫这个方法?我有一个问题,我试图在方法中呈现模态视图控制器viewDidLoad.我的解决方案是将此调用移至该viewDidAppear:方法.

我的假设是视图控制器的观点是不是在窗口的视图层次的,它已经加载点(当viewDidLoad发送邮件),但它在窗口层次结构已经呈现后(当viewDidAppear:发送消息) .


警告

如果你做一个呼叫presentViewController:animated:completion:viewDidAppear:其中总是被提出的模态视图控制器每当视图控制器的看法出现(这是有道理的!)等呈现模态视图控制器永远不会消失,你可能会遇到一个问题.. .

也许这不是呈现模态视图控制器的最佳位置,或者可能需要保留一些额外的状态,这允许呈现视图控制器决定它是否应该立即呈现模态视图控制器.

  • 我希望我可以两次投票.我刚刚遇到这个问题,并且在线程中发现我上次看到这个时已经投票了. (38认同)
  • @James你是对的,视图显然不在层次结构中,直到*viewWillAppear已经解析并且一旦调用了viewDidAppear.如果这是我的问题,我会接受这个答案;) (6认同)
  • @james谢谢.使用ViewDidAppear也解决了我的问题.说得通. (6认同)
  • 请注意,当您更改viewDidAppear中的VC时,这会导致使用Animation执行segue.导致背景的闪烁/显示. (6认同)
  • 是的诀窍是viewWillAppear:(BOOL)动画,因为它是正确的.更重要的是你必须在方法中调用super,如[super viewDidAppear:animated]; 没有这个它不起作用. (2认同)

Chr*_*let 63

另一个潜在原因:

当我无意中两次呈现相同的视图控制器时,我遇到了这个问题.(performSegueWithIdentifer:sender:按下按钮时调用一次,直接连接到按钮的第二次调用).

实际上,两个segues同时开火,我得到了错误: Attempt to present X on Y whose view is not in the window hierarchy!

  • 我有同样的错误,你的答案在这里帮助我弄清楚发生了什么,这确实是这个错误,因为你先生修好了,谢谢你,+ 1 (3认同)

Jon*_*nny 36

viewWillLayoutSubviewsviewDidLayoutSubviews(iOS 5.0+)可用于此目的.它们比viewDidAppear更早被调用.

  • 它们仍然在其他场合使用,所以我认为它们可能在视图的"生命周期"中被多次调用. (3认同)

abd*_*har 22

要显示主视图的任何子视图,请使用以下代码

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (yourCurrentViewController.presentedViewController) 
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}

[yourCurrentViewController presentViewController:composeViewController animated:YES completion:nil];
Run Code Online (Sandbox Code Playgroud)

要从主视图中关闭任何子视图,请使用以下代码

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (yourCurrentViewController.presentedViewController) 
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}

[yourCurrentViewController dismissViewControllerAnimated:YES completion:nil];
Run Code Online (Sandbox Code Playgroud)


sun*_*ppy 17

当我尝试在其中呈现视图控制器时,我也遇到了这个问题UIViewController.我试过詹姆斯贝德福德的答案.它可以工作,但我的应用程序将首先显示背景1或2秒.

经过研究我终于找到了解决这个问题的另一种方法是使用子视图控制器.

- (void)viewDidLoad
{
    ...
    [self.view addSubview: navigationViewController.view];
    [self addChildViewController: navigationViewController];
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 我觉得你不见了[navigationViewController didMoveToParentViewController:self] (9认同)
  • 我尝试了你的代码,以及foFox的建议,当我从它的父母那里删除它时,它不会消失.Lololol.仍然坚持没有修复. (2认同)

小智 14

可能和我一样,你的根本错了 viewController

我想ViewControllernon-UIViewController上下文中显示

所以我不能使用这样的代码:

[self presentViewController:]
Run Code Online (Sandbox Code Playgroud)

所以,我得到一个UIViewController:

[[[[UIApplication sharedApplication] delegate] window] rootViewController]
Run Code Online (Sandbox Code Playgroud)

出于某种原因(逻辑错误),这rootViewController是预期的(正常UIViewController).然后我纠正错误,替换rootViewController为a UINavigationController,问题就消失了.


Mar*_*rcy 14

Swift 5 - 后台线程

如果在后台线程上执行警报控制器,则可能会出现“尝试呈现...其视图不在窗口层次结构中”错误。

所以这:

present(alert, animated: true, completion: nil)
    
Run Code Online (Sandbox Code Playgroud)

已修复:

DispatchQueue.main.async { [weak self] in
    self?.present(alert, animated: true, completion: nil)
}
Run Code Online (Sandbox Code Playgroud)


Agg*_*sor 7

TL; DR您只能拥有一个rootViewController及其最近提供的一个.因此,当它已经呈现一个尚未被解除的视图控制器时,不要尝试让视图控制器呈现另一个视图控制器.

在做了一些我自己的测试后,我得出了一个结论.

如果你有一个想要呈现所有内容的rootViewController,那么你可能会遇到这个问题.

这是我的rootController代码(open是我从根目录呈现viewcontroller的快捷方式).

func open(controller:UIViewController)
{
    if (Context.ROOTWINDOW.rootViewController == nil)
    {
        Context.ROOTWINDOW.rootViewController = ROOT_VIEW_CONTROLLER
        Context.ROOTWINDOW.makeKeyAndVisible()
    }

    ROOT_VIEW_CONTROLLER.presentViewController(controller, animated: true, completion: {})
}
Run Code Online (Sandbox Code Playgroud)

如果我连续两次打开(不管时间是多少),这将在第一次打开时正常工作,但不会在第二次打开时工作.第二次打开尝试将导致上述错误.

但是,如果我关闭最近显示的视图然后调用open,当我再次调用open(在另一个viewcontroller上)时它可以正常工作.

func close(controller:UIViewController)
{
    ROOT_VIEW_CONTROLLER.dismissViewControllerAnimated(true, completion: nil)
}
Run Code Online (Sandbox Code Playgroud)

我得出的结论是,只有MOST-RECENT-CALL的rootViewController在视图Hierarchy上(即使你没有关闭它或删除一个视图).我试着玩所有的加载器调用(viewDidLoad,viewDidAppear,并进行延迟的调度调用),我发现我能让它工作的唯一方法是只从最顶层的视图控制器调用present.


Ash*_*hal 6

我在Swift 4.2上遇到了类似的问题,但我的视图没有从视图周期中呈现出来。我发现我有多个 segue 需要同时呈现。所以我使用了 dispatchAsyncAfter。

func updateView() {

 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in

// for programmatically presenting view controller 
// present(viewController, animated: true, completion: nil)

//For Story board segue. you will also have to setup prepare segue for this to work. 
 self?.performSegue(withIdentifier: "Identifier", sender: nil)
  }
}
Run Code Online (Sandbox Code Playgroud)


Ada*_*hns 5

我的问题,我在执行SEGUE UIApplicationDelegatedidFinishLaunchingWithOptions方法之前,我打电话makeKeyAndVisible()的窗口.


Geo*_*e_E 5

在我的情况下,我无法将我的置于班级覆盖中。所以,这就是我得到的:

let viewController = self // I had viewController passed in as a function,
                          // but otherwise you can do this


// Present the view controller
let currentViewController = UIApplication.shared.keyWindow?.rootViewController
currentViewController?.dismiss(animated: true, completion: nil)

if viewController.presentedViewController == nil {
    currentViewController?.present(alert, animated: true, completion: nil)
} else {
    viewController.present(alert, animated: true, completion: nil)
}
Run Code Online (Sandbox Code Playgroud)