addChildViewController 和 addSubview 的区别?

Difference between addChildViewController and addSubview?

这两种方法都将视图添加为父视图的子视图,并且视图可以接收事件。什么时候使用哪一个?

它们非常不同。 addChildViewController 将视图控制器与父容器视图控制器相关联,而 addSubview 将视图添加到要添加到的视图的视图层次结构中。在前一种情况下,当新的子视图控制器是其父视图控制器的选定视图控制器时,它将负责处理事件。想想标签栏控制器——每个标签都有自己关联的 "child" 视图控制器,它在父标签栏控制器的内容区域中显示其视图,并在标签中选择相应的标签时处理该视图内的任何用户交互酒吧。当你有一个自定义容器视图并且想要将一个新的视图控制器添加到它的 childViewControllers 属性 时,你应该只使用 addChildViewController。如果您只是想向视图层次结构中添加一个可以接收事件的新视图(听起来就是这样),addSubview 是最佳选择。 "Implementing a Container View Controller" section explains what addChildViewController is for.

可从iOS 5, addChildViewController:

- (void)addChildViewController:(UIViewController *)childController NS_AVAILABLE_IOS(5_0);

方法允许您将任何视图控制器作为子视图控制器添加到其他视图控制器,但首先它会从 childController 中删除任何父视图控制器,然后将其作为子视图控制器添加到指定的控制器。

子控制器只不过是 UIViewController 的一个实例,因此它将提供视图控制器的功能(即它将接收 -(void)viewWillAppear、-(void)viewWillDisappear 等事件等等,就像正常的 UIViewController 一样)。

另一方面

 - (void)addSubview:(UIView *)view;

addSubview: 会将任何视图添加为任何其他视图的 subview

这不是选择什么时候使用,而是要求使用特定方法的类型。

例如-

如果你有一个 UIViewController 的实例,那么你肯定会使用 addChildViewController:(你也可以使用 presentModalViewControllerpushViewController)并且如果你有一个实例UIView 绝对不是你必须使用 addSubview.

注意:您还可以将视图控制器的视图作为子视图添加到任何其他视图。

addChildViewControllerUIViewController class 中的方法并且 addSubviewUIView class

两者的行为完全不同。

addChildViewController 只是将一个视图控制器放在当前视图控制器的前面。您必须管理控制器的流程。此方法仅供自定义容器视图控制器的实现调用。

addSubview 添加另一个视图作为该对象的视图的子视图。

这完全取决于您希望如何管理新的子视图。如果你希望新的子视图由当前视图的视图控制器管理(例如,你正在添加一些简单的东西,比如一些 UILabel 对象),你只需调用 addSubview。另一方面,如果新的子视图有自己的视图控制器(即它是足够复杂的视图集合,具有丰富的功能,你想用它自己的控制器封装所有这些复杂性来管理这个新子视图所做的一切)然后您调用 addChildViewController 来添加新的视图控制器,但随后也调用 addSubview

因此,请注意 addChildViewController 本身对视图没有任何作用。您通常会立即通过添加其视图的调用来跟随它,例如这是 View Controller Programming Guide for iOS 的 Implementing a Custom Container View Controller 部分中的一个稍微澄清的示例:

[self addChildViewController:childViewController];        // add subview's view controller
childViewController.view.frame = ...                      // specify where you want the new subview
[self.view addSubview:childViewController.view];          // now you can add the child view controller's view
[childViewController didMoveToParentViewController:self]; // now tell the child view controller that the adding of it and its views is all done

所以,这不是addSubview vs addChildViewController的问题,而是addSubview vs addChildViewController+addSubview的问题。如果您调用 addChildViewController,您这样做的目的是在某个时候调用 addSubview 以获取其视图。

坦率地说,addSubviewaddChildViewController+addSubview 这个问题很少是我们思考这个问题的方式。一种更合乎逻辑的思考方式是确定这个新视图是否有自己的视图控制器。如果是,则执行 addChildViewController 调用序列。如果没有,您只需调用 addSubview.

有关视图控制器包含的详细介绍(例如,API 的基本原理、保持视图层次结构与视图控制器层次结构同步的重要性等),请参阅 WWDC 2011 视频 Implementing UIViewController Containment.

根据一些测试,我发现:如果子视图控制器没有添加到父视图控制器(假设父视图控制器在根视图控制器下),只有子视图控制器的视图被添加到父视图控制器的视图查看,然后:

  • 子视图控制器仍然可以接收与视图直接相关的消息,例如- viewWillAppear:- viewWillLayoutSubviews

但是

  • 子视图无法接收某些系统消息,例如- willRotateToInterfaceOrientation:duration:

不过,我现在不能提供消息列表。

addChildViewController用于防止添加的子视图控制器释放,即父视图控制器将持有对子视图控制器的强引用。

知道 MVC 表示模型-视图-控制器:

如果您只打算添加 视图,则使用 addSubview。例如添加标签、按钮。

但是,如果您打算使用 view + controller,则必须使用 addChildViewController 添加其 controller 和 ALSO addSubView 添加它的 view。例如添加另一个 viewController,tableViewController。

另外:

有两类事件被转发到子视图控制器:

1-外观方法:

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

2-旋转方法:

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

如果您不这样做,您将 运行 陷入问题的示例是

有关更多信息,我强烈建议查看this问题的答案。