警告:不建议在分离的视图控制器上显示视图控制器


180

在我的应用中,我正在使用导航控制器。稍后在某些视图中,我将presentViewController用于显示缩放的图像。另外,我没有使用情节提要或笔尖。

我仅在iOS 7中收到此错误。它在iOS 6和更早的版本中运行良好:

不建议在分离的视图控制器上显示视图控制器


我还没弄清楚。但是在我的应用程序中,我没有将任何viewcontroller分配给window.rootviewcontroller。我将视图添加到窗口。可能那是我的原因。但不确定...
— Gagan Joshi

@GaganJoshi您上面提到的原因可能不是原因。即使我也面临着同样的问题。在我们的项目中,我正在为window.rootviewcontroller分配一个视图控制器。
— Rajesh

1
我认为其他注释正确地将其与有关rootViewController和窗口连接的内容联系起来。我还没有弄清楚,但是我可以通过直接在rootViewController上而不是在导航控制器或其子级之一上显示控制器来解决此问题。
— Rich Waters

Answers:


207

为了避免在推送导航中收到警告,您可以直接使用:

[self.view.window.rootViewController presentViewController:viewController animated:YES completion:nil];

然后在模态视图控制器中,当一切完成后,您可以调用:

[self dismissViewControllerAnimated:YES completion:nil];


我正在用以下行代码“ [self.view.window.rootViewController presentViewController:viewController animation:YEScomplete:nil];”显示图像选择器。但是,无法通过以下行关闭[]:[self dismissViewControllerAnimated:YEScomplete:nil];” dismisscontroller的任何其他选择
— 2014年

@keyurbhalodiya您需要从modalView调用dismissViewController方法以使其工作。因此,如果从带有[viewA.window.rootViewController presentViewController:viewB]的viewA中显示了一个名为viewB的视图,则需要在viewB中添加一个按钮,该按钮与调用[self dismissViewControllerAnimated]的自定义动作相关。比较清楚吗?
— cdescours 2014年

11
不呈递的ViewController在IOS 8.
— 拉杰什孔雀


31
使用self.navigationController为我做了。
— 布兰登·扎查里

62

此警告的原因是我在不是全尺寸视图的小视图上显示了视图控制器。下面给出的是我的项目的图像。在上面单击四个选项。用户导航到其他childviewcontroller的视图。(其工作方式类似于tabViewcontroller)。但是childviewcontroller包含较小的视图。因此,如果我们呈现来自childviewcontroller的视图,则会发出此警告。

主细节视图

为了避免这种情况,您可以在childviewcontroller的父级上显示一个视图

  [self.parentViewController presentViewController:viewController animated:YES completion:nil];

1
[self.view.window.rootViewController.navigationController pushViewController:YOUR_VIEW_CONTROLER动画:是];
— Fede Cugliandolo

1
“在不是全尺寸视图的小视图上显示视图控制器。” 完全正确 辛苦了
— Fattie

59

等待 viewDidAppear():

如果尝试在视图实际出现之前呈现视图控制器,例如在viewWillAppear()或更早的时间呈现视图,也会出现此错误。尝试在其后viewDidAppear()或内部呈现另一个视图。


9
换句话说,请勿在中显示任何视图控制器viewDidLoad()!我犯了很多次这个错误……
— T Blank

谢谢你的帮助。我在viewDidLoad中有代码,它试图在最后显示一个对话框。
— ArdenDev '16

在不进行动画测试的单元/集成测试中,出现此错误。
— mixtly87

21

就我而言,我将sampleViewController的视图添加为子视图,然后尝试从的视图sampleViewController(这里self是UIViewController实例)中显示弹出窗口:

[self.view addSubview:sampleViewController.view];

正确的方法应该在下面:

// make sure the vc has been added as a child view controller as well
[self addChildViewController:sampleViewController];
[self.view addSubview:sampleViewController.view];
[sampleViewController didMoveToParentViewController:self];

顺便说一句,这也适用于在表格视图单元格中显示弹出窗口的情况,您只需要确保已将表格视图控制器也添加为子视图控制器即可。


另外调用didMoveToParentViewController。请检查“添加和删除ChildViewController”:gist.github.com/tomohisa/2897676
— Jakehao 2015年

@jianzong我记得没有必要做最后一步。无论如何,让我添加一下,谢谢你的建议。:)
— Kjuly 2015年

是的,没有最后一步就可以工作。我认为它的目的是通知parentViewController,以便它将调用某些方法来执行某些操作。:)
— Jakehao 2015年

2
它对我[self addChildViewController:sampleViewController];
— 有用

16

我认为问题在于您没有适当的视图控制器层次结构。设置应用程序的rootviewcontroller,然后通过在其上推动或呈现新的视图控制器来显示新视图。让每个视图控制器管理他们的视图。只有容器视图控制器(如tabbarviewcontroller)应该将其他视图控制器视图添加到自己的视图中。阅读视图控制器编程指南,以了解有关如何正确使用视图控制器的更多信息。https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/


14

迅捷3

对于任何对此绊脚石的人,这是一个迅速的答案。

self.parent?.present(viewController, animated: true, completion: nil)

9

我有几乎相同的问题。原因是我试图在另一个控制器上显示“某些”控制器,并且在完成动画后,我将显示控制器设置为root。完成此操作后,所有其他出现的控制器都会警告我:“ 不建议在分离的视图控制器上显示视图控制器 ”。而且我解决了这个警告,只是将“某些”控制器设置为root,而一开始没有任何提示。

已移除:

[[self rootController] presentViewController:controller animated:YES completion:^{

       [self window].rootViewController = controller;

       [[self window] makeKeyAndVisible];}];

只需以root身份进行,无需任何演示即可:

 [[self window] setRootViewController:controller];

1
这正是我的问题。试图用UIModalTransitionStyleCrossDissolve呈现它,然后使其成为rootViewController。之后,所有其他演示都失败,并显示给定的警告消息。只需将其设置为没有动画的rootViewcontroller就可以了。谢谢!
— 贝尔纳多·奥利维拉

7

解决方案之一是如果您有childviewcontroller,那么您只需在给定的条件下在其父控件上呈现viewcontroller

[self.parentViewController presentViewController:viewController animated:YES completion:nil];

对于解雇,请使用相同的dismissview控制器。

[self dismissViewControllerAnimated:YES completion:nil];

这对我来说是完美的解决方案。


7

[self.navigationController presentViewController:xxx animated:YES completion:nil]在iOS 8中使用。


5

试试这个代码

UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:<your ViewController object>];

[self.view.window.rootViewController presentViewController:navigationController animated:YES completion:nil];

4

TabBarController如果它是一个TabBarController基于应用程序,请尝试演示。

[self.tabBarController presentViewController:viewController animated:YES completion:nil];

原因可能self是的孩子,TabBarController而您正试图从中提出礼物ChildViewController。


4

是的,在显示另一个视图中的Alert控制器时,我也遇到了同样的警告消息。后来我通过从父视图控制器呈现警报控制器来避免这种情况,如下所示:

[self.parentViewController presentViewController:alertController animated:YES completion:nil];

3

您需要添加视图控制器,该视图控制器会将新控制器显示为父视图控制器的子代。

假设您有MainViewController,然后添加了一个名为controllerA的新控制器,然后要从controllerA中呈现一个名为controllerB的新控制器。

您必须编写如下内容:

[self addChildViewController:controllerA]; //self is yourMainViewController
[self.view addsubView:controllerA.view]; 

在controllerA内,您可以在没有警告的情况下展示新控制器

[self presentViewController:controllerB animated:YES completion:nil]; //self is controllerA

3

在Swift 4.1和Xcode 9.4.1中

解决方法是

DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})

如果这样写我会得到同样的错误

let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
    })
alert.addAction(defaultAction)

present(alert, animated: true, completion: nil) 

我遇到了同样的错误

Presenting view controllers on detached view controllers is discouraged <MyAppName.ViewController: 0x7fa95560Z070>.

完整的解决方案是

let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
     })
alert.addAction(defaultAction)
//Made Changes here    
DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})

像这样通过DispatchQueue运行它对我来说很有效。我正在对模态视图控制器执行performSegue,从我的第一个视图控制器上的viewDidLoad调用(用于定向新用户的首次启动介绍屏幕)。加载正常,但生成警告。在DispatchQueue异步调用中包装performSegue调用可以消除该警告。谢谢!
— Grant Neufeld

1

确保您首先具有一个根视图控制器。您可以在中进行设置didFinishLaunchingWithOptions。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    [window setRootViewController:viewController];
}

1

产生此警告的原因很多。我的是因为我有一个从ViewController连接到另一个将以模态显示的segue。但是,我要呈现的ViewController是由PageViewController动态生成的。这就是为什么它在情节提要中分离的原因。我的应用不会因此而崩溃;但我想使警告保持沉默。


1

我到达了这个线程,那里有一个自定义导航栏,并且正在通过它调用AlertViewController。

我必须将其作为孩子添加到主视图控制器中。然后,我可以在没有任何警告的情况下称呼它。

您应该添加您的 Zoomed Image View Controller为主ViewController的子级。

(例如)

[self addChildViewController:ZoomedImageViewController];

然后您就可以调用ZoomedImageViewController

[self presentViewController:ZoomedImageViewController];

1

许多答案是正确的。

  • 检查您的presentingViewController是否具有parentViewController。
  • 如果否,请将其添加到应添加的位置
  • 否则,递归检查它的parentViewController是否具有parentViewController,直到每个viewController都具有parent

当我的同事向BViewController添加AViewController时,这个问题发生了。不知何故,他只是将AViewController的视图添加到BViewController的视图。

通过添加bViewController.addChild(aViewController)进行修复


1
谢谢!在Hero.shared.transition完成块中添加addChild完全解决了我的问题。
— Landnbloc

0

这取决于您是否要在任何类型的UIViewController中显示警报或类似内容。

您可以使用以下代码示例:

UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Alert" message:@"Example" preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:nil];

[alert addAction:cancelAction];


[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:alert animated:true completion:nil];

使用您的代码,它将无法正常工作并提供此日志Attempt to present <UIAlertController: 0x7fc01a1eb600> on <ViewController: 0x7fc019821e00> whose view is not in the window hierarchy!
— Naveed Abbas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.