其观点不在窗口层次结构中

刚开始使用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]; 

你从哪里调用这个方法? 我有一个问题,我试图在viewDidLoad方法中提供一个模式视图控制器。 我的解决scheme是将此调用移动到viewDidAppear:方法。

我的推测是,视图控制器的视图不在窗口的视图层次结构中,它已经被加载(当viewDidLoad消息被发送时),但是在它被呈现之后它在窗口层次结构中(当viewDidAppear:消息已发送)。


警告

如果你确实调用了presentViewController:animated:completion:viewDidAppear:你可能遇到一个问题,即当视图控制器的视图出现时,总是呈现模态视图控制器(这是合理的!),所以模态视图控制器被呈现将永远不会消失…

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

另一个潜在原因:

当我不小心提交了两次相同的视图控制器时,我遇到了这个问题。 (一旦执行了performSegueWithIdentifer:sender:当button被按下时被调用,并且第二次使用直接连接到button的segue)。

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

viewWillLayoutSubviewsviewDidLayoutSubviews (iOS 5.0+)可用于此目的。 它们比viewDidAppear早。

当我尝试在viewDidLoad呈现视图控制器时,我也遇到了这个问题。 我试过詹姆斯·贝德福德的答案。 它的作品,但我的应用程序将显示背景1或2秒。

经过研究,我终于find解决这个问题的另一种方法就是使用子视图控制器。

 - (void)viewDidLoad { ... [self.view addSubview:navigationViewController.view]; [self addChildViewController:navigationViewController]; ... } 

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

 UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController; while (yourCurrentViewController.presentedViewController) { yourCurrentViewController = yourCurrentViewController.presentedViewController; } [yourCurrentViewController presentViewController:composeViewController animated:YES completion:nil]; 

对于从主视图closures任何子视图,请使用以下代码

 UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController; while (yourCurrentViewController.presentedViewController) { yourCurrentViewController = yourCurrentViewController.presentedViewController; } [yourCurrentViewController dismissViewControllerAnimated:YES completion:nil]; 

可能像我一样,你有一个错误的根viewController

我想在non-UIViewController上下文中显示一个ViewController

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

 [self presentViewController:] 

所以,我得到一个UIViewController:

 [[[[UIApplication sharedApplication] delegate] window] rootViewController] 

出于某种原因(逻辑错误), rootViewController是不是预期的东西(一个正常的UIViewController )。 然后我纠正错误,用UINavigationControllerreplacerootViewController ,问题就消失了。

我的问题是我正在执行在UIApplicationDelegatedidFinishLaunchingWithOptions方法中的segue,然后在窗口上调用makeKeyAndVisible()

我遇到过同样的问题。 问题是,执行SegueWithIdentifier是由通知触发的,只要我通知主线程的警告消息已经消失。

如果您有播放video的AVPlayer对象,则必须先暂停video。

我有同样的问题。 我不得不embedded一个导航控制器,并通过它显示控制器。 以下是示例代码。

 - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. UIImagePickerController *cameraView = [[UIImagePickerController alloc]init]; [cameraView setSourceType:UIImagePickerControllerSourceTypeCamera]; [cameraView setShowsCameraControls:NO]; UIView *cameraOverlay = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 768, 1024)]; UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"someImage"]]; [imageView setFrame:CGRectMake(0, 0, 768, 1024)]; [cameraOverlay addSubview:imageView]; [cameraView setCameraOverlayView:imageView]; [self.navigationController presentViewController:cameraView animated:NO completion:nil]; // [self presentViewController:cameraView animated:NO completion:nil]; //this will cause view is not in the window hierarchy error } 

在我看来, 故事梗中的残酷是一种破碎 。 删除segue(并再次创build完全相同的segue)解决了这个问题。

如果有帮助,我的问题是非常愚蠢的。 当然,完全是我的错。 一个通知触发了一个调用模态的方法。 但是我没有正确地移除通知,所以在某些时候,我会有多个通知,所以模态会被多次调用。 当然,在调用模态之后,调用它的视图控制器不再处于视图层次结构中,这就是我们看到这个问题的原因。 我的情况也造成了一堆其他问题,就像你所期望的那样。

所以总结一下,无论你在做什么,都要确保模态不会被多次调用

我已经结束了这样一个代码,最终对我(Swift),考虑到你想从几乎任何地方显示一些viewController 。 当没有rootViewController可用时,这段代码显然会崩溃,这是开放的结局。 它也不包括通常需要切换到UI线程使用

 dispatch_sync(dispatch_get_main_queue(), { guard !NSBundle.mainBundle().bundlePath.hasSuffix(".appex") else { return; // skip operation when embedded to App Extension } if let delegate = UIApplication.sharedApplication().delegate { delegate.window!!.rootViewController?.presentViewController(viewController, animated: true, completion: { () -> Void in // optional completion code }) } } 

我有这个问题,根本原因是多次订阅button点击处理程序(TouchUpInside)。

它是在ViewWillAppear中订阅的,自从我们添加导航到另一个控制器之后,它被多次调用,然后放松回来。

TL; DR您只能拥有1个rootViewController及其最近提供的一个。 所以不要试图让viewcontroller提供另一个viewcontroller,当它已经提交了一个没有被解雇的。

在做了一些我自己的testing后,我得出了一个结论。

如果你有一个rootViewController,你想呈现一切,那么你可以遇到这个问题。

这是我的rootController代码(打开是我从根目录呈现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: {}) } 

如果我连续两次打开(不pipe时间如何),这在第一次打开时就可以正常工作,而不是在第二次打开时打开。 第二次打开尝试将导致上述错误。

但是,如果我closures最近呈现的视图,然后调用打开,当我再次打开(在另一个视图控制器上)时,它工作得很好。

 func close(controller:UIViewController) { ROOT_VIEW_CONTROLLER.dismissViewControllerAnimated(true, completion: nil) } 

我所得出的结论是,只有MOST-RECENT-CALL的rootViewController在视图层次上(即使你没有closures它或删除视图)。 我试着玩所有的加载程序调用(viewDidLoad,viewDidAppear,并做延迟调度调用),我发现唯一的办法,我可以得到它的工作是只从最上面的视图控制器调用存在。

从embedded在容器中的视图控制器执行segue时,也可以获得此警告。 正确的解决scheme是从容器的父级使用segue,而不是从容器的视图控制器。

必须写下线。

 self.searchController.definesPresentationContext = true 

代替

 self.definesPresentationContext = true 

在UIViewController

这工作很好,试试这个。 链接

 UIViewController *top = [UIApplication sharedApplication].keyWindow.rootViewController; [top presentViewController:secondView animated:YES completion: nil]; 

随着Swift 3 …

另一个可能的原因是,发生在我身上的是从一个tableViewCell到另一个Storyboard上的ViewController。 我还使用了override func prepare(for segue: UIStoryboardSegue, sender: Any?) {}当单元格被点击。

我解决了这个问题,从ViewController到ViewController。

我也有这个问题,但是与时间无关。 我正在使用一个单身来处理场景,我把它设置为主持人。 换句话说,“自我”没有挂钩任何东西。 我只是把它的内部“场景”作为新的主持人,而且它是有效的。 (你知道它的意思后,Voila就失去了它的感觉,呵呵)。

所以,这不是关于“神奇地find正确的方式”,而是关于理解你的代码在哪里以及它在做什么。 我很高兴苹果给出了这样一个简单英文的警告信息,即使对此感慨。 荣誉给那个苹果开发者!

如果其他解决scheme由于某种原因而看起来不太好,那么仍然可以使用这个延迟为0的老式workaround ,如下所示:

 dispatch_after(0, dispatch_get_main_queue(), ^{ finishViewController *finished = [self.storyboard instantiateViewControllerWithIdentifier:@"finishViewController"]; [self presentViewController:finished animated:NO completion:NULL]; }); 

虽然我没有看到任何logging的保证,你的VC将在时间调度块计划执行的视图层次结构,我已经发现它会工作得很好。

使用例如0.2秒的延迟也是一种select。 而最好的东西 – 这样你就不需要在viewDidAppear:弄乱布尔variablesviewDidAppear: