【问题标题】:Warning :-Presenting view controllers on detached view controllers is discouraged警告:- 不鼓励在分离的视图控制器上显示视图控制器
【发布时间】:2013-11-22 08:01:29
【问题描述】:

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

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

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

【问题讨论】:

  • 我还没弄明白。但在我的应用程序中,我没有将任何视图控制器分配给 window.rootviewcontroller。我正在向窗口添加视图。可能这就是我的原因。但不确定...
  • @GaganJoshi 您上面提到的原因可能不是原因。即使我面临同样的问题。在我们的项目中,我将视图控制器分配给 window.rootviewcontroller 。
  • 我认为其他 cmets 正确地将这与 rootViewController 和窗口连接相关联。我还没有完全弄清楚,但我已经能够通过直接在 rootViewController 上而不是在导航控制器或其子之一上显示控制器来解决这个问题。

标签: ios iphone cocoa-touch ios7 warnings


【解决方案1】:

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

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

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

[self dismissViewControllerAnimated:YES completion:nil];

【讨论】:

  • 我正在使用此行代码“[self.view.window.rootViewController presentViewController:viewController animated:YES completion:nil];”呈现图像选择器但无法使用此行“[self dismissViewControllerAnimated:YES completion:nil];”关闭 poicker 视图解雇控制器的任何替代选项
  • @keyurbhalodiya 您需要从modalView 调用dismissViewController 方法以使其工作。因此,如果您使用 [viewA.window.rootViewController presentViewController:viewB] 从 viewA 显示名为 viewB 的视图,则需要在 viewB 中添加一个按钮,例如,与调用 [self dismissViewControllerAnimated] 的自定义操作相关联。是不是更清楚了?
  • 在 iOS 8 中不显示视图控制器。
  • 对于 iOS 8:[self.view.window.rootViewController.navigationController
  • 使用 self.navigationController 为我做了。
【解决方案2】:

等待viewDidAppear()

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

【讨论】:

  • 换句话说,不要在viewDidLoad() 中显示任何视图控制器,各位!这个错误我犯过很多次了……
  • 感谢帮助。我在 viewDidLoad 中有代码,它试图在最后显示一个对话框。
  • 在不使用动画进行测试的情况下运行单元/集成测试时出现此错误。
  • 是的,正如你所说!如果不是这条消息,我可能不得不重构。
【解决方案3】:

这个警告的原因是我在一个不是全尺寸视图的小视图上展示了一个视图控制器。下面给出的是我的项目的图像。点击上面的四个选项。用户导航到不同的 childviewcontroller 的视图。(它像 tabViewcontroller 一样工作)。但是 childviewcontroller 包含小尺寸的视图。因此,如果我们从 childviewcontroller 呈现一个视图,它会给出这个警告。

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

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

【讨论】:

  • [self.view.window.rootViewController.navigationController pushViewController:YOUR_VIEW_CONTROLER animated:YES];
  • “在一个非全尺寸视图的小视图上显示视图控制器。” ...完全正确。干得好。
【解决方案4】:

就我而言,我将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
  • @jianzong 我记得没有必要做最后一步。无论如何,让我添加它,谢谢您的建议。 :)
  • 是的,它无需最后一步即可工作。我认为它的目的是通知 parentViewController 以便它会调用一些方法来做某事。 :)
  • 它对我有用,我在另一个控制器中使用一个控制器视图 - (以编程方式查看容器),我没有添加 [self addChildViewController:sampleViewController];,现在我添加了这个,谢谢
【解决方案5】:

斯威夫特 3

对于遇到此问题的任何人,这里是快速的答案。

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

【讨论】:

    【解决方案6】:

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

    【讨论】:

      【解决方案7】:

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

      已删除:

      [[self rootController] presentViewController:controller animated:YES completion:^{
      
             [self window].rootViewController = controller;
      
             [[self window] makeKeyAndVisible];}];
      

      只需以root身份制作,无需任何演示:

       [[self window] setRootViewController:controller];
      

      【讨论】:

      • 这正是我的问题。试图用 UIModalTransitionStyleCrossDissolve 呈现它,然后使其成为 rootViewController。之后,所有其他演示都失败并显示给定的警告消息。只需将其设置为没有动画的 rootViewcontroller 就可以了。谢谢!
      【解决方案8】:

      解决方案之一是如果您有 childviewcontroller 所以您只需通过给定的方式在其父级上显示viewcontroller

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

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

      [self dismissViewControllerAnimated:YES completion:nil];
      

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

      【讨论】:

        【解决方案9】:

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

        【讨论】:

          【解决方案10】:

          试试这个代码

          UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:<your ViewController object>];
          
          [self.view.window.rootViewController presentViewController:navigationController animated:YES completion:nil];
          

          【讨论】:

            【解决方案11】:

            在 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 调用可以消除警告。谢谢!
            【解决方案12】:

            如果它是基于 TabBarController 的应用程序,请尝试在 TabBarController 上进行演示。

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

            原因可能是 selfTabBarController 的孩子,而您正试图从 ChildViewController 呈现。

            【讨论】:

              【解决方案13】:

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

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

              【讨论】:

                【解决方案14】:

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

                假设你有你的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
                

                【讨论】:

                  【解决方案15】:

                  我在这个线程上找到了一个自定义导航栏,并通过它调用了一个 AlertViewController。

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

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

                  (例如)

                  [self addChildViewController:ZoomedImageViewController];
                  

                  然后你就可以调用你的 ZoomedImageViewController

                  [self presentViewController:ZoomedImageViewController];
                  

                  【讨论】:

                    【解决方案16】:

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

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

                    【讨论】:

                      【解决方案17】:

                      这个警告有很多原因。我的是因为我有一个从 ViewController 连接到另一个将以模态方式呈现的 segue。但是,我展示的 ViewController 是由 PageViewController 动态生成的。这就是它在情节提要中分离的原因。我的应用程序不会因此而崩溃;但我想消除警告。

                      【讨论】:

                        【解决方案18】:

                        这取决于你是否想在任何类型的 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 &lt;UIAlertController: 0x7fc01a1eb600&gt; on &lt;ViewController: 0x7fc019821e00&gt; whose view is not in the window hierarchy!
                        【解决方案19】:

                        很多答案都是对的。

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

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

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

                        【讨论】:

                        • 谢谢!在我的 Hero.shared.transition 完成块中添加 addChild 完全解决了我的问题。
                        猜你喜欢
                        • 1970-01-01
                        • 2018-02-21
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2015-01-25
                        • 2017-02-16
                        • 1970-01-01
                        相关资源
                        最近更新 更多