ios addChildViewController 实际上是做什么的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17192005/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What does addChildViewController actually do?
提问by Mark Amery
I'm just dipping my feet for the first time into iOS development, and one of the first things I've had to do is implement a custom container view controller- lets call it SideBarViewController
- that swaps out which of several possible child view controllers it shows, almost exactly like a standard Tab Bar Controller. (It's pretty much a Tab Bar Controllerbut with a hideable side menu instead of a tab bar.)
我只是第一次涉足 iOS 开发,我必须做的第一件事就是实现一个自定义容器视图控制器——让我们称之为SideBarViewController
——它会换出几个可能的子视图控制器中的哪一个显示,几乎与标准Tab Bar Controller完全一样。(它几乎是一个标签栏控制器,但有一个可隐藏的侧边菜单而不是标签栏。)
As per the instructions in the Apple documentation, I call addChildViewController
whenever I add a child ViewController to my container. My code for swapping out the current child view controller being shown by the SideBarViewController
looks like this:
根据 Apple 文档中的说明,addChildViewController
每当我将子 ViewController 添加到我的容器时,我都会调用。我用于换出当前子视图控制器的代码如下所示SideBarViewController
:
- (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];
}
Then I started trying to figure out just what addChildViewController
does here, and I realised that I have no idea. Besides sticking the new ViewController
in the .childViewControllers
array, it seems to have no effect on anything. Actions and outlets from the child controller's view to the child controller that I've set on the storyboard still work just fine even if I never call addChildViewController
, and I can't imagine what else it could affect.
然后我开始试图弄清楚addChildViewController
这里有什么,我意识到我不知道。除了ViewController
在.childViewControllers
数组中粘贴 new 之外,它似乎对任何东西都没有影响。从子控制器的视图到我在情节提要上设置的子控制器的动作和出口仍然可以正常工作,即使我从不调用addChildViewController
,而且我无法想象它还会影响什么。
Indeed, if I rewrite my code to not call addChildViewController
, and instead look like this...
事实上,如果我重写我的代码不调用addChildViewController
,而是看起来像这样......
- (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;
}
... then my app still works perfectly, so far as I can tell!
...那么我的应用程序仍然可以完美运行,据我所知!
The Apple documentation doesn't shed much light on what addChildViewController
does, or why we're supposed to call it. The entire extent of the relevant description of what the method does or why it should be used in its section in the UIViewController
Class Referenceis, at present:
Apple 文档并没有说明它是addChildViewController
做什么的,或者我们为什么要这么称呼它。目前,在UIViewController
Class Reference 的部分中对该方法的作用或为什么应该使用它的相关描述的整个范围是:
Adds the given view controller as a child. ... This method is only intended to be called by an implementation of a custom container view controller. If you override this method, you must call super in your implementation.
将给定的视图控制器添加为子级。...此方法仅旨在由自定义容器视图控制器的实现调用。如果覆盖此方法,则必须在实现中调用 super。
There's also this paragraph earlier on the same page:
在同一页面上还有这一段:
Your container view controller must associate a child view controller with itself before adding the child's root view to the view hierarchy. This allows iOS to properly route events to child view controllers and the views those controllers manage. Likewise, after it removes a child's root view from its view hierarchy, it should disconnect that child view controller from itself. To make or break these associations, your container calls specific methods defined by the base class. These methods are not intended to be called by clients of your container class; they are to be used only by your container's implementation to provide the expected containment behavior.
Here are the essential methods you might need to call:
addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:
在将子视图的根视图添加到视图层次结构之前,您的容器视图控制器必须将子视图控制器与其自身相关联。这允许 iOS 正确地将事件路由到子视图控制器和这些控制器管理的视图。同样,在从其视图层次结构中删除子视图的根视图后,它应该断开该子视图控制器与其自身的连接。为了建立或打破这些关联,您的容器调用由基类定义的特定方法。这些方法不打算由容器类的客户端调用;它们只能由您的容器实现使用,以提供预期的遏制行为。
以下是您可能需要调用的基本方法:
addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:
but it doesn't offer any clue as to what the 'events' or 'expected containment behavior' that it's talking about are, or why (or even when) calling these methods is 'essential'.
但它没有提供关于它所谈论的“事件”或“预期的收容行为”是什么,或者为什么(甚至何时)调用这些方法是“必不可少的”的任何线索。
The examples of custom container view controllers in the "Custom Container View Controllers" section of the Apple documentation all call this method, so I assume that it serves some important purpose beyond just popping the child ViewController onto an array, but I can't figure out what that purpose is. What does this method do, and why should I call it?
Apple 文档的“自定义容器视图控制器”部分中的自定义容器视图控制器示例都调用了此方法,因此我认为它除了将子 ViewController 弹出到数组之外还有一些重要用途,但我想不通目的是什么。这个方法有什么作用,我为什么要调用它?
采纳答案by nevan king
I was wondering about this question too. I watched Session 102 of the WWDC 2011videos and Mr. View Controller, Bruce D. Nilo, said this:
我也想问这个问题。我观看了 WWDC 2011视频的Session 102,View Controller 先生Bruce D. Nilo说:
viewWillAppear:
,viewDidAppear:
, etc have nothing to do withaddChildViewController:
. All thataddChildViewController:
does is to say "This view controller is a child of that one" and it has nothing to do with view appearance. When they get called is associated with when views move in and out of the window hierarchy.
viewWillAppear:
,viewDidAppear:
等与addChildViewController:
. 所有这一切addChildViewController:
确实是说“此视图控制器是一个的孩子”和它无关,与视图的外观。当它们被调用时与视图移入和移出窗口层次结构的时间相关联。
So it seems that the call to addChildViewController:
does very little. The side effects of the call are the important part. They come from the parentViewController
and childViewControllers
relationships. Here are some of the side effects that I know:
因此,似乎对调用的addChildViewController:
作用很小。调用的副作用是重要的部分。它们来自于parentViewController
和childViewControllers
关系。以下是我所知道的一些副作用:
- Forwarding appearance methods to child view controllers
- Forwarding rotation methods
- (Possibly) forwarding memory warnings
- Avoiding inconsistent VC hierarchies, especially in
transitionFromViewController:toViewController:…
where both VCs need to have the same parent - Allowing custom container view controllers to take part in State Preservation and Restoration
- Taking part in the responder chain
- Hooking up the
navigationController
,tabBarController
, etc properties
- 将外观方法转发给子视图控制器
- 转发轮换方式
- (可能)转发内存警告
- 避免不一致的 VC 层次结构,尤其是在
transitionFromViewController:toViewController:…
两个 VC 需要具有相同父级的情况下 - 允许自定义容器视图控制器参与状态保存和恢复
- 参与响应者链
- 挂钩的
navigationController
,tabBarController
等属性
回答by Hejazi
I think an example is worth a thousand words.
我认为一个例子值一千字。
I was working on a library app and wanted to show a nice notepad view that appears when the user wants to add a note.
我正在开发一个图书馆应用程序,并希望显示一个漂亮的记事本视图,当用户想要添加注释时会出现该视图。
After trying some solutions, I ended up inventing my own custom solution to show the notepad. So when I want to show the notepad, I create a new instance of NotepadViewController
and add its root view as a subview to the main view. So far so good.
在尝试了一些解决方案后,我最终发明了自己的自定义解决方案来显示记事本。因此,当我想显示记事本时,我创建了一个新实例NotepadViewController
并将其根视图作为子视图添加到主视图中。到现在为止还挺好。
Then I noticed that the notepad image is partially hidden under the keyboard in landscape mode.
然后我注意到记事本图像在横向模式下部分隐藏在键盘下。
So I wanted to change the notepad image and shift it up. And to do so, I wrote the proper code in willAnimateRotationToInterfaceOrientation:duration:
method, but when I ran the app nothing happened! And after debugging I noticed that none of UIViewController
's rotation methods is actually called in NotepadViewController
. Only those methods in the main view controller are being called.
所以我想更改记事本图像并将其向上移动。为此,我在willAnimateRotationToInterfaceOrientation:duration:
方法中编写了正确的代码,但是当我运行应用程序时什么也没发生!在调试之后,我注意到UIViewController
实际上没有调用任何旋转方法NotepadViewController
。只有主视图控制器中的那些方法被调用。
To solve this, I needed to call all the methods from NotepadViewController
manually when they're called in the main view controller. This will soon make things complicated and create an extra dependency between unrelated components in the app.
为了解决这个问题,我需要NotepadViewController
在主视图控制器中调用所有方法时手动调用它们。这很快会使事情变得复杂,并在应用程序中不相关的组件之间创建额外的依赖关系。
That was in the past, before the concept of child view controllers is introduced. But now, you only need to addChildViewController
to the main view controller and everything will just work as expected without any more manual work.
那是过去,在引入子视图控制器的概念之前。但是现在,您只需要到 addChildViewController
主视图控制器,一切都将按预期工作,无需更多手动工作。
Edit:There are two categories of events that are forwarded to child view controllers:
编辑:有两类事件被转发到子视图控制器:
1- Appearance Methods:
1-外观方法:
- viewWillAppear:
- viewDidAppear:
- viewWillDisappear:
- viewDidDisappear:
2- Rotation Methods:
2- 旋转方法:
- willRotateToInterfaceOrientation:duration:
- willAnimateRotationToInterfaceOrientation:duration:
- didRotateFromInterfaceOrientation:
You can also control what event categories you want to be forwarded automatically by overriding shouldAutomaticallyForwardRotationMethods
and shouldAutomaticallyForwardAppearanceMethods
.
您还可以通过覆盖shouldAutomaticallyForwardRotationMethods
和来控制要自动转发的事件类别shouldAutomaticallyForwardAppearanceMethods
。
回答by Gianluca Tranchedone
-[UIViewController addChildViewController:]
only adds the passed in view controller in an array of viewControllers that a viewController (the parent) wants to keep reference of. You should actually add those viewController's views on screen yourself by adding them as a subviews of another view (e.g. the parentViewController's view). There's also a convenience object in Interface Builder to use childrenViewControllers in Storyboards.
-[UIViewController addChildViewController:]
仅将传入的视图控制器添加到视图控制器(父级)想要保留引用的视图控制器数组中。实际上,您应该通过将它们添加为另一个视图的子视图(例如 parentViewController 的视图)来自己在屏幕上添加这些 viewController 的视图。Interface Builder 中还有一个方便的对象,用于在 Storyboards 中使用 childrenViewController。
Previously, to keep reference of other viewControllers of which you used the views of, you had to keep manual reference of them in @properties. Having a build-in property like childViewControllers
and consequently parentViewController
is a convenient way to manage such interactions and build composed viewControllers like the UISplitViewController that you find on iPad apps.
以前,为了保持对您使用其视图的其他视图控制器的引用,您必须在@properties 中手动引用它们。拥有像childViewControllers
and 因此的内置属性parentViewController
是管理此类交互和构建组合视图控制器的便捷方式,例如您在 iPad 应用程序上找到的 UISplitViewController。
Moreover, childrenViewControllers also automatically receive all the system events that the parent receives: -viewWillAppear, -viewWillDisappear, etc. Previously you should have called this methods manually on your "childrenViewControllers".
此外,childrenViewControllers 还会自动接收父级接收到的所有系统事件:-viewWillAppear、-viewWillDisappear 等。以前您应该在“childrenViewControllers”上手动调用这些方法。
That's it.
就是这样。