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

当前回答

这适用于呈现任何视图控制器,如果你有可用的导航控制器。 self.navigationController ?。present(MyViewController, animated: true, completion: nil) 此外,我可以能够呈现警报和邮件控制器也。

其他回答

该消息显示为警告,有时代码拒绝工作。(!引文:更新的SDK可能有严格的规则)。

我遇到这种情况的原因不止一个,主要是复杂的视图控制器场景。举个例子。

Scenario: MainViewController (responsible to load: ViewControllerA & ViewControllerB)

从MainViewController中呈现ViewControllerA,并且在不解散ViewControllerA的情况下,尝试从MainViewController中呈现viewControllerB(使用委托方法)。

在这个场景中,你必须确保你的viewcontrollerera被解散,然后ViewControllerB被调用。

因为在呈现ViewControllerA之后(ViewControllerA开始负责显示视图和视图控制器,当MainViewController尝试加载另一个视图控制器时,它拒绝抛出警告)。

另一个潜在原因:

当我不小心两次呈现同一个视图控制器时,我就遇到了这个问题。(第一次使用performSegueWithIdentifer:sender:当按钮被按下时调用,第二次使用直接连接到按钮的segue)。

实际上,两个segue同时被触发,我得到了错误:试图在Y上显示X,其视图不在窗口层次结构中!

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

我想在非uiviewcontroller上下文中显示一个ViewController,

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

[self presentViewController:]

我得到一个UIViewController

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

由于某种原因(逻辑错误),rootViewController是其他的东西比预期的(一个正常的UIViewController)。然后我纠正了这个错误,用UINavigationController替换了rootViewController,问题就解决了。

在主窗口中,可能总是会出现与显示警报不兼容的过渡。为了允许在应用程序生命周期的任何时候显示警报,您应该有一个单独的窗口来完成这项工作。

/// independant window for alerts
@interface AlertWindow: UIWindow

+ (void)presentAlertWithTitle:(NSString *)title message:(NSString *)message;

@end

@implementation AlertWindow

+ (AlertWindow *)sharedInstance
{
    static AlertWindow *sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[AlertWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
    });
    return sharedInstance;
}

+ (void)presentAlertWithTitle:(NSString *)title message:(NSString *)message
{
    // Using a separate window to solve "Warning: Attempt to present <UIAlertController> on <UIViewController> whose view is not in the window hierarchy!"
    UIWindow *shared = AlertWindow.sharedInstance;
    shared.userInteractionEnabled = YES;
    UIViewController *root = shared.rootViewController;
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    alert.modalInPopover = true;
    [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
        shared.userInteractionEnabled = NO;
        [root dismissViewControllerAnimated:YES completion:nil];
    }]];
    [root presentViewController:alert animated:YES completion:nil];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    self.userInteractionEnabled = NO;
    self.windowLevel = CGFLOAT_MAX;
    self.backgroundColor = UIColor.clearColor;
    self.hidden = NO;
    self.rootViewController = UIViewController.new;

    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(bringWindowToTop:)
                                               name:UIWindowDidBecomeVisibleNotification
                                             object:nil];

    return self;
}

/// Bring AlertWindow to top when another window is being shown.
- (void)bringWindowToTop:(NSNotification *)notification {
    if (![notification.object isKindOfClass:[AlertWindow class]]) {
        self.hidden = YES;
        self.hidden = NO;
    }
}

@end

在设计上总是成功的基本用法:

[AlertWindow presentAlertWithTitle:@"My title" message:@"My message"];

用Swift 3…

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

我通过创建一个从ViewController到ViewController的segue来解决这个问题。