ios - addChildViewController实际上做了什么?

我刚刚第一次踏入iOS开发阶段,而我必须要做的第一件事就是实现一个自定义的容器视图控制器 - 让我们称之为UIViewController - 交换出几个中的哪一个 它显示的可能的子视图控制器,几乎完全像标准的Tab Bar Controller。 (它几乎是一个标签栏控制器,但有一个可隐藏的侧面菜单而不是标签栏。)

根据Apple文档中的说明,每当我将一个子ViewController添加到我的容器时,我都会调用UIViewController。 用于交换ViewController显示的当前子视图控制器的代码如下所示:

- (void)showViewController:(UIViewController *)newViewController {
    UIViewController* oldViewController = [self.childViewControllers 
                                           objectAtIndex:0];

    [oldViewController removeFromParentViewController];
    [oldViewController.view removeFromSuperview];

    newViewController.view.frame = CGRectMake(
        0, 0, self.view.frame.size.width, self.view.frame.size.height
    );
    [self addChildViewController: newViewController];
    [self.view addSubview: newViewController.view];
}

然后我开始试图找出UIViewController在这里做了什么,我意识到我不知道。 除了在.childViewControllers阵列中粘贴新的ViewController之外,它似乎对任何事情都没有影响。 从儿童控制器的视图到我在故事板上设置的儿童控制器的操作和出口仍然正常工作,即使我从未打过电话addChildViewController,我无法想象它还能影响到什么。

事实上,如果我重写我的代码不要拨打UIViewController,而是看起来像这样......

- (void)showViewController:(UIViewController *)newViewController {

    // Get the current child from a member variable of `SideBarViewController`
    UIViewController* oldViewController = currentChildViewController;

    [oldViewController.view removeFromSuperview];

    newViewController.view.frame = CGRectMake(
        0, 0, self.view.frame.size.width, self.view.frame.size.height
    );
    [self.view addSubview: newViewController.view];

    currentChildViewController = newViewController;
}

...然后我的应用程序仍然完美,据我所知!

Apple文档并没有详细说明UIViewController的作用,或者为什么我们应该调用它。 目前,在UIViewController类参考的部分中,该方法的相关描述或其原因的相关描述的整个范围是:

将给定的视图控制器添加为子级。  ...   此方法仅用于通过自定义容器视图控制器的实现来调用。 如果重写此方法,则必须在实现中调用super。

此段落也在同一页面上:

在将子视图的根视图添加到视图层次结构之前,容器视图控制器必须将子视图控制器与其自身关联。 这允许iOS正确地将事件路由到子视图控制器以及这些控制器管理的视图。 同样,在从视图层次结构中删除子视图的根视图后,它应该断开该子视图控制器与其自身的连接。 要建立或断开这些关联,容器会调用基类定义的特定方法。 这些方法不是由容器类的客户端调用的; 它们仅由容器的实现使用,以提供预期的包含行为。

以下是您可能需要调用的基本方法:

addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:

但它没有提供关于“事件”的任何线索。 或者预期的遏制行为' 他们所谈论的是,或者为什么(甚至何时)调用这些方法是必不可少的'。

"自定义容器视图控制器中的自定义容器视图控制器的示例" Apple文档的一部分都调用了这个方法,所以我认为除了将子ViewController弹出到数组之外它还有一些重要的用途,但是我无法弄清楚它的用途是什么。 这种方法做了什么,为什么要调用它?

Mark Amery asked 2019-08-13T17:53:24Z
3个解决方案
106 votes

我认为一个例子胜过千言万语。

我正在开发一个图书馆应用程序,并希望显示一个很好的记事本视图,当用户想要添加注释时出现。

enter image description here

在尝试了一些解决方案后,我最终发明了自己的自定义解决方案来显示记事本。 因此,当我想要显示记事本时,我创建了一个新的实例shouldAutomaticallyForwardAppearanceMethods并将其根视图作为子视图添加到主视图中。 到现在为止还挺好。

然后我注意到,在横向模式下,记事本图像部分隐藏在键盘下方。

enter image description here

所以我想改变记事本图像并将其向上移动。 为此,我在shouldAutomaticallyForwardAppearanceMethods方法中编写了正确的代码,但是当我运行应用程序时没有发生任何事情! 在调试之后,我注意到在NotepadViewController中实际上没有调用UIViewController的旋转方法。只调用主视图控制器中的那些方法。

为了解决这个问题,我需要在主视图控制器中调用时手动调用shouldAutomaticallyForwardAppearanceMethods中的所有方法。 这将很快使事情变得复杂,并在应用程序中的不相关组件之间创建额外的依赖关系。

那是在过去,在引入子视图控制器的概念之前。 但是现在,您只需要shouldAutomaticallyForwardAppearanceMethods到主视图控制器,一切都将按预期工作,无需任何手动工作。

编辑:转发到子视图控制器的事件有两类:

1-外观方法:

- viewWillAppear:
- viewDidAppear:
- viewWillDisappear:
- viewDidDisappear:

2-轮换方法:

- willRotateToInterfaceOrientation:duration:
- willAnimateRotationToInterfaceOrientation:duration:
- didRotateFromInterfaceOrientation:

您还可以通过覆盖shouldAutomaticallyForwardAppearanceMethodsshouldAutomaticallyForwardAppearanceMethods来控制要自动转发的事件类别。

Hejazi answered 2019-08-13T17:56:23Z
91 votes

我也想知道这个问题。 我观看了WWDC 2011视频的第102场会议和视觉控制先生Bruce D. Nilo先生说:

navigationController,tabBarController等等与childViewControllers无关。所有addChildViewController:所做的就是说"这个视图控制器是那个视频控制器的一个孩子" 它与视图外观无关。 当调用进入和退出窗口层次结构时,它们被调用时会被关联。

因此,似乎对navigationController的调用很少。 呼叫的副作用是重要的部分。 它们来自tabBarControllerchildViewControllers的关系。 以下是我所知道的一些副作用:

  • 将外观方法转发到子视图控制器
  • 转发轮换方法
  • (可能)转发内存警告
  • 避免不一致的VC层次结构,特别是在navigationController中,两个VC都需要具有相同的父级
  • 允许自定义容器视图控制器参与状态保存和恢复
  • 参与响应者链
  • 连接navigationController,tabBarController等属性
nevan king answered 2019-08-13T17:54:45Z
9 votes

childViewControllers仅在视图控制器数组中添加传入的视图控制器,viewController(父级)希望保留对其的引用。 实际上,您应该将这些viewController视图添加为另一个视图的子视图(例如parentViewController的视图),从而自己在屏幕上添加这些视图。 Interface Builder中还有一个便利对象,可以在Storyboard中使用childrenViewControllers。

以前,为了保留您使用其视图的其他viewControllers的引用,您必须在@properties中保留它们的手动引用。 拥有内置属性,如childViewControllers,因此parentViewController是管理此类交互和构建组合viewControllers的便捷方式,如您在iPad应用程序上找到的UISplitViewController。

此外,childrenViewControllers还会自动接收父接收的所有系统事件:-viewWillAppear,-viewWillDisappear等。以前,您应该在" childrenViewControllers"上手动调用此方法。

而已。

Gianluca Tranchedone answered 2019-08-13T17:57:08Z
translate from https://stackoverflow.com:/questions/17192005/what-does-addchildviewcontroller-actually-do