What exactly is the point of adding childViewController? - objective-c

I got a parentViewController.
The parentViewController has 3 children.
AnnController,
BobController,
CharlieController
(not real name)
At any time only a view of one such controller may exist. Transition is done with:
[self transitionFromViewController:fromController toViewController:toViewController duration:duration options:options animations:animations completion:^(BOOL finished)
Everything works well.
But then what's the point of adding Ann, Bob, and Charlie as a child of Parent?
At first I thought it's so that viewWillAppear and viewWillDisappear got called automatically during transitionFromViewController
But it's called anyway whether the viewController is a child or not.
It could be so that viewWillAppear and viewWillDisappear got called when parents got called. But that's easy to do.
Of course, only the view that's actually in the view hiearchy of ParentController.view will have their viewWillAppear and viewWillDisappear be called right? Or is it?
So what's exactly does the fact that Ann, Bob, and Charlie is the child of Parent Controller do?
At the Parent's viewWillAppear, will it go through all of it's child and call their viewWillAppear if and only if the childController's view is part of the hierarchy? Or what?
Actually what does the fact that
Note: I am well aware of what view containtment mean. I asked what exactly does it do? For example, one of the answer said that it pass on rotation. Yes. But does it do so for all child or only child whose view is in the parentViewController.view hierarchy? Or what?

Short Anwwer:
adding childViewController allow you to redirect events in a view controller to other controllers that has been defined has its children.
Long Answer:
addChildViewController is part of iOS 5 and later. It is a feature called "view controller containment". The basic idea behind this is that you can embed your view controllers into other view controllers of your own. It is powerful because it allows you to write your own tabViewController or customNavigationController for e.g.
The main thing about View controller containment is that it tries to ensure that all contained view controllers will get the appropriate messages. An easy example will be when you rotate your device, if you didn't add the addChildViewController the rotation changes event won't be passed down to your view hierarchy.
The view cycle like the calls you are mentioning (viewWillAppear, viewWillDisappear) are managed by the view controller so it is a different story.
Take a look to the official doc to get a good understanding of the power of custom container controller.

Related

When will viewWill/DidAppear/Disappear is called anyway and how exactly does it work?

I understand that viewWillAppear will be called when duh.... when the the view is about to appear.
But how does IOS know that a controller's view is about to appear?
When exactly that and how it is implemented?
For example, does the childController.view check first that window is one of it's super ancestors? Does the view has a pointer to it's controller? How exactly that works? Does everytime a view is added it check whether it's window is it's super ancestor and whether it is the view outlet of a UIViewController?
For example, if I add childcontroller.view but not to a subview of any view that's being called. Will viewWillAppear called?
Does the childController need to be the a child of a parentController so that viewWillAppear of the childController will be called when the parentController's viewWillAppear is called automatically?
The view is loaded by your controller using the - (void)loadView method. This method is implemented to load a blank view or a view from a nib/storyboard. You only need to override it if you really need to create a view hierarchy from scratch.
All of the magic happens when the value of the view property is first requested and the controller detects the value is nil. All of the life cycle method calls are handled by the UIViewController. There is nothing you need to do other than implement the methods if you need them. Remember one thing: There is no guarantee the view has been loaded until the - (void)viewDidLoad method has been called.
Everything I've learned about controllers how they work has come from the View Controller Programming Guide.

MVC and UIButtons

I have an iPad project I'm working on that dynamically creates a number of buttons that I need to add to the main view of my application. I was planning on firing a method that lives inside my View from my ViewController...say it's called add_buttons. It's my impression that in the MVC pattern, the view should handle the rendering of buttons and the general display, but the controller should handle the interaction. I'm also under the impression that it's bad design for the view to "know" about the view controller.
So I guess my question is, should I have my button tap logic contained in my controller? If so, how do I handle the separation? If I'm creating the buttons in my view, then it would have to have a reference to the view controller to use as the delegate for the event handler. If I create them in the controller, then I feel like I need to set certain UI elements in the controller which seems wrong to me. I know I'm missing something obvious but searching so far has proven fruitless.
Can anyone point me in the right direction?
The button tap logic most certainly belongs in the controller.
The code that creates the buttons probably belongs in the controller too. However, it would make sense to include a view method that returns a button with its appearance configured but not its behaviour.
Some general pointe:
View controllers and their view are very tightly coupled.
If in doubt it's best to put the code in the view controller.
A views interface should deal with primitive data types (e.g. strings, numbers, images). Views should not need to know the specifics of model objects.
Also, the naming convention for methods lowerCamelCase. Eg:add_button should be addButton.
when you add button to view,
[myButton addTarget:nil action:#selector(myButtonPressed) forControlEvents:UIControlEventTouchUpInside];
in view controller add
-(void)myButtonPressed {
}
with target:nil event will be handled by first controller containing this view
I rescently finished a project where I had to dynamically create UIViews which contained both UITextfields and UILabels.My approach to this problem was to call the "addViews" function from within the view controller. I figured this to be a better and easier approach rather than dealing with view controllers from inside the UIView. I have tested my approach and works completely fine (dynamically change UIView size and adding other UIViews with a UITextfield and a UILabel).

Modal view controllers calling other's "viewDidLoad"

I have a bunch of pages I am chaining together and presenting as modal view controllers. THey all have viewDidLoad methods. It seems that when one is loaded though it calls the viewDidLoad methods of ones in the background too. How can I stop this? Thanks!
You can't. The viewDidLoad method will get called when the view is loaded. Asking a view controller for its view loads the view.
Consider moving code into your viewWillAppear:(BOOL)animated method. That way it will only get called before the view is actually shown to the user.

Is it wise to "nest" UIViewControllers inside other UIViewControllers like you would UIViews?

I've got a fairly complex view, for me anyway, that has a few "trays" with custom interface items on them. They slide in and out of my root view. I'd like to nest (addSubview) the items inside the view. Each needs some setup before being displayed...and none can be configured in IB (they're subclasses of UIView).
I'm wondering if it makes sense to subclass UIViewController for each "tray" and then have the VC's view property point to the "tray" view which I can populate with my custom UIView objects. This way I can leverage the viewDidLoad, etc... methods in UIViewController.
I'm not aware of others doing this - at least in the few samples I've looked at. It would create a situation where there would be multiple view controllers being displayed on the screen at once. from the Navigation controller itself on down to the rootViewController and its view and then any number (well, screen size permitting) of these small trayViewControllers. If so, how's the responder chain work? i assume it'd go from lowest UIView to its enclosing VC, then to that VC's parent view, then that view's VC, etc. etc. repeat, repeat.. up to UIApplication... am I asking for trouble?
OR, do I just stick with UIViews and adding subviews into subviews, etc. etc..
Prior to iOS 5.0 this will specifically not recommended because the nested view controllers' lifecycle events – viewWillAppear, etc. – won't be called. See Abusing UIViewControllers.
With multiple UIViewController’s views visible at once some of those controllers may not receive important messages like -viewWillAppear: or -didReceiveMemoryWarning. Additionally some of their properties like parentViewController and interfaceOrientation may not be set or updated as expected.
iOS 5.0 added containment UIViewControllers that correctly handles those lifecycle events by adding child view controllers.
- (void)addChildViewController:(UIViewController *)childController
I spent countless hours trying to get nested view controllers to work in iOS 4. I eventually did, but it required a lot of glue code that was easy to get wrong. Then I saw the warning in the docs.
I'm trying to do the same thing, but was dissuaded from your approach by Apple's documentation, which states that "You should not use view controllers to manage views that fill only a part of their window—that is, only part of the area defined by the application content rectangle. If you want to have an interface composed of several smaller views, embed them all in a single root view and manage that view with your view controller."
My experience on what you are trying to do has been a good one. I try to keep nib files as simple as possible, so I take any posible "subview" and encapsulate it in its own nib file with it's own view controller, therefore I end up having nested view controllers.
In one of my apps I have a very complex table view cell, that has a subview. So I ended up having a hierarchy that goes like this: the tableview controller on the top level, the tableviewcell's controllers for each row and inside each of these a subviewcontroller for the subview inside each cell.
And everything works fine.
Pardon my english.

How return back info from a child to parent in a NavigationController

I wonder what is the proper way to get back some message from a child view.
I have a object that is edited in the child view. I wanna see in the TableView their modifications.
However, I don't know a clean way to do it (I don't like a singleton here).
Is possible get notified when the Child view dissapear and get some info on that?
You can use the UIViewController notifications viewWillDisappear: and viewDidDisappear: to be notified right before a certain UIView is about to disappear and right after it disappears respectively. Note that most of the various UIKit objects (including UITableView) are subclasses of UIView.
IMHO, the "correct" way would be to implement a custom protocol in the view's controller (probably navigation controller in your case) or the application delegate and have the child view communicate using it when it gets the viewWillDisappear and/or viewWillDisappear notifications (as mentioned in Adam's reply). Similarly, in the parent view you can refresh the necessary information in the viewWillAppear handler.
This way, the parent view is getting its data from the delegate and not directly from a specific child view, which maintains MVC in your design.
You could also issue a notification (using NSNotificationCenter) that the parent would be subscribed to listen for - that has the side benefit that other classes could be notified as well.
But if it's a pretty strict relationship where only the sub view and master table will care, you probably should set your table view controller as a delegate of the subview and have the subview call the delegate directly (a protocol as mentioned is a good idea for something like this).