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

Warning :-Presenting view controllers on detached view controllers is discouraged

提问人:Gagan Joshi 提问时间:11/10/2013 最后编辑:NareshGagan Joshi 更新时间:11/21/2023 访问量:149987

问:

在我的应用程序中,我使用的是导航控制器。稍后,在某些视图中,我用于显示缩放的图像。 此外,我没有使用故事板或笔尖。presentViewController

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

在分离的视图控制器上显示视图控制器是 气馁

iOS iPhone Cocoa-Touch iOS7 警告

评论

0赞 Gagan Joshi 11/14/2013
我还没有弄清楚。但是在我的应用程序中,我没有将任何视图控制器分配给window.rootviewcontroller。我正在向窗口添加视图。也许这就是我的原因。但不确定...
1赞 Rajesh 11/20/2013
@GaganJoshi 你上面提到的原因可能不是原因。甚至我也面临同样的问题。在我们的项目中,我将视图控制器分配给 window.rootviewcontroller 。
1赞 Rich Waters 11/23/2013
我认为其他评论正确地将此与rootViewController和窗口连接有关。我还没有完全弄清楚这一点,但是我已经能够通过将控制器直接呈现在rootViewController上而不是导航控制器或其子控制器之一上来解决此问题。
0赞 5/7/2018
阿扎克西斯明白了:stackoverflow.com/a/31877722/5306470
0赞 Victor Engel 9/8/2023
嗯 - 我也得到了这个,但现在我将忽略它。我的应用程序是一个绘图应用程序。在应用程序中,可以编辑曲线。编辑曲线是通过将曲线编辑器显示为表单表来完成的。同时,曲线编辑器允许用户选择颜色。我有一个颜色选择器。颜色选取器的一部分是一个视图,用于显示显示视图控制器的选择。从主视图控制器获取该详细信息是没有意义的。相关部分位于曲线编辑视图控制器上。我注意到它说的是气馁 - 而不是禁止。

答:

15赞 Ed Ytterbrink 12/10/2013 #1

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

211赞 cdescours 1/9/2014 #2

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

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

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

[self dismissViewControllerAnimated:YES completion:nil];

评论

0赞 kb920 4/9/2014
我正在向图像选择器提供以下行代码“[self.view.window.rootViewController presentViewController:viewController animated:YES completion:nil];”但无法用以下行“[self dismissViewControllerAnimated:YES completion:nil];”dismisscontroller 的任何替代选项
0赞 cdescours 4/14/2014
@keyurbhalodiya 您需要从 modalView 调用 dismissViewController 方法才能使其工作。因此,如果使用 [viewA.window.rootViewController presentViewController:viewB] 从 viewA 中显示名为 viewB 的视图,则需要在 viewB 中添加一个按钮,例如,与调用 [self dismissViewControllerAnimated] 的自定义操作相关联。是不是更清楚了?
11赞 Rajesh Maurya 9/3/2014
未在 iOS 8 中显示视图控制器。
1赞 Fede Cugliandolo 9/26/2014
对于 iOS 8:[self.view.window.rootViewController.navigationController
33赞 Brandon Zacharie 3/17/2015
使用为我做到了。self.navigationController
1赞 samwize 4/14/2014 #3

确保您有一个根视图控制器。您可以在 中设置它。didFinishLaunchingWithOptions

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    [window setRootViewController:viewController];
}
9赞 averem 6/27/2014 #4

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

删除:

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

       [self window].rootViewController = controller;

       [[self window] makeKeyAndVisible];}];

只需以 root 身份创建,无需任何演示:

 [[self window] setRootViewController:controller];

评论

1赞 Bernardo Oliveira 3/8/2016
这正是我的问题。试图用 UIModalTransitionStyleCrossDissolve 呈现它,然后使其成为 rootViewController。之后,所有其他演示文稿都失败,并显示给定的警告消息。只需将其设置为没有动画的 rootViewcontroller 即可。谢谢!
64赞 Gagan Joshi 8/7/2014 #5

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

master detail view

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

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

评论

1赞 Fede Cugliandolo 9/26/2014
[self.view.window.rootViewController.navigationController pushViewController:YOUR_VIEW_CONTROLER animated:YES];
2赞 Fattie 2/17/2017
“在非全尺寸视图的小视图上呈现视图控制器。”...完全。干得好。
7赞 Gagan Joshi 10/8/2014 #6

其中一个解决方案是,如果你有 childviewcontroller,那么你只需在它的父级上给出

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

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

[self dismissViewControllerAnimated:YES completion:nil];

这是完美的解决方案,适用于我。

7赞 Tao Fang 10/14/2014 #7

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

22赞 Kjuly 2/23/2015 #8

就我而言,我添加了一个视图作为子视图,然后尝试从视图(这里是一个实例)显示一个弹出框:sampleViewControllersampleViewControllerselfUIViewController

[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];

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

评论

0赞 Jakehao 4/11/2015
此外,调用 didMoveToParentViewController。请签出添加和删除 ChildViewController:gist.github.com/tomohisa/2897676
0赞 Kjuly 4/11/2015
@jianzong我记得没有必要做最后一步。无论如何,让我添加它,谢谢您的建议。:)
0赞 Jakehao 4/11/2015
是的,它无需最后一步即可工作。我认为它的目的是通知parentViewController,以便它将调用一些方法来做某事。:)
2赞 anjnkmr 12/1/2017
它对我有用,我在另一个控制器中使用一个控制器视图 - (容器视图以编程方式),我没有添加,现在我添加了这个,谢谢[self addChildViewController:sampleViewController];
4赞 Sivasagar Palakurthy 5/27/2015 #9

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

[self.parentViewController presentViewController:alertController animated:YES completion:nil];
82赞 Azaxis 8/7/2015 #10

俟:viewDidAppear()

如果您尝试在视图实际出现之前显示视图控制器,例如在视图中或更早版本中显示视图,也会出现此错误。 尝试在它之后或内部呈现另一个视图。viewWillAppear()viewDidAppear()

评论

15赞 T Blank 2/17/2016
换句话说,不要在 中显示任何视图控制器 , people!我犯过很多次这个错误......viewDidLoad()
0赞 ArdenDev 7/11/2016
谢谢,这很有帮助。我在viewDidLoad中有代码,它试图在最后显示一个对话框。
0赞 mixtly87 10/20/2016
我在运行单元/集成测试时收到此错误,而我没有使用动画进行测试。
0赞 kikiwora 10/8/2020
是的,这和你说的一模一样!如果不是这条消息,我可能不得不重构。
3赞 Chuy47 8/22/2015 #11

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

假设你有 MainViewController,然后添加一个名为 controllerA 的新控制器,然后你希望从 controllerA 提供一个名为 controllerB 的新控制器

你必须写这样的东西:

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

在控制器 A 中,您可以在不发出警告的情况下显示新控制器

[self presentViewController:controllerB animated:YES completion:nil]; //self is controllerA
5赞 Vlad 3/12/2016 #12

试试这段代码

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

[self.view.window.rootViewController presentViewController:navigationController animated:YES completion:nil];
1赞 Lee Probert 4/27/2016 #13

此警告的原因有很多。我的是因为我有一个从 ViewController 连接到另一个 segue,它将以模式呈现。但是,我演示的 ViewController 是由 PageViewController 动态生成的。这就是它在 Storyboard 中分离的原因。我的应用程序不会因此而崩溃;但我想让警告保持沉默。

20赞 Jeremie 5/12/2017 #14

斯威夫特 3

对于任何绊倒这一点的人,这里有一个快速的答案。

self.parent?.present(viewController, animated: true, completion: nil)
4赞 Warif Akhand Rishi 8/22/2017 #15

尝试展示它是否是基于应用程序。TabBarControllerTabBarController

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

原因可能是 的子项,而您正试图从 .selfTabBarControllerChildViewController

1赞 Fabio 3/4/2018 #16

这取决于你是否要在 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];

评论

0赞 Naveed Abbas 7/30/2019
对于您的代码,它不起作用并给出此日志Attempt to present <UIAlertController: 0x7fc01a1eb600> on <ViewController: 0x7fc019821e00> whose view is not in the window hierarchy!
9赞 Naresh 8/28/2018 #17

在 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)
})

评论

0赞 Grant Neufeld 3/13/2020
像这样通过 DispatchQueue 运行它对我有用。我正在对模态视图控制器执行 PerformSegue,该控制器从我的第一个视图控制器(用于定位新用户的首次启动介绍屏幕)上的 viewDidLoad 调用。它加载正常,但生成警告。将 performSegue 调用包装在 DispatchQueue 异步调用中可消除警告。谢谢!
2赞 Naveed Abbas 7/30/2019 #18

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

我不得不将它作为一个孩子添加到我的主视图控制器中。然后我可以在没有任何警告的情况下调用它。

您应该将 your 添加为主 ViewController 的子项。Zoomed Image View Controller

(例如)

[self addChildViewController:ZoomedImageViewController];

然后,你就可以调用 ZoomedImageViewController

[self presentViewController:ZoomedImageViewController];
1赞 Jerome Li 2/7/2020 #19

许多答案都是对的。

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

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

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

评论

1赞 landnbloc 3/16/2020
谢谢!在我的 Hero.shared.transition 完成块中添加 addChild 完全解决了我的问题。