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


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(这里selfUIViewController实例)中显示弹出窗口:

[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.