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

当前回答

viewWillLayoutSubviews和viewDidLayoutSubviews (iOS 5.0+)可以用于此目的。它们在viewDidAppear之前被调用。

其他回答

如果你有播放视频的AVPlayer对象,你必须先暂停视频。

你只能有1个rootViewController,它是最近出现的一个。所以不要尝试让一个视图控制器呈现另一个视图控制器当它已经呈现了一个没有被解散的视图控制器。

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

如果你有一个rootViewController你想要显示所有东西,那么你就会遇到这个问题。

下面是我的rootController代码(打开是从根节点显示视图控制器的快捷方式)。

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: {})
}

如果我在一行中调用open两次(不管时间流逝),这将在第一个开放上工作,但不是在第二个开放上。第二次打开尝试将导致上述错误。

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

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

我的结论是,只有MOST-RECENT-CALL的rootViewController在视图层次结构上(即使您没有解散它或删除视图)。我试着玩所有的加载器调用(viewDidLoad, viewDidAppear,并做延迟调度调用),我发现我能让它工作的唯一方法是从最顶层的视图控制器调用present。

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

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


谨慎

如果你确实调用了viewDidAppear:中的presentViewController:animated:completion:,你可能会遇到这样一个问题,即每当视图控制器的视图出现时,模态视图控制器总是被呈现(这是有意义的!),因此模态视图控制器被呈现永远不会消失……

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

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

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

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

[yourCurrentViewController presentViewController:composeViewController animated:YES completion:nil];

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

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

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

[yourCurrentViewController dismissViewControllerAnimated:YES completion:nil];

我已经结束了这样一个代码,最终工作给我(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
        })
    }
}