What does addChildViewController actually do?
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.
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.
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.
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.
Edit: There are two categories of events that are forwarded to child view controllers:
1- Appearance Methods:
- viewWillAppear:
- viewDidAppear:
- viewWillDisappear:
- viewDidDisappear:
2- Rotation Methods:
- willRotateToInterfaceOrientation:duration:
- willAnimateRotationToInterfaceOrientation:duration:
- didRotateFromInterfaceOrientation:
You can also control what event categories you want to be forwarded automatically by overriding shouldAutomaticallyForwardRotationMethods
and shouldAutomaticallyForwardAppearanceMethods
.
I was wondering about this question too. I watched Session 102 of the WWDC 2011 videos and Mr. View Controller, Bruce D. Nilo, said this:
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.
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:
- 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
-[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.
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.
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".
That's it.