communication between two controllers in iOS MVC implementation - ios

I've two different views which have two different controllers(firstVC and secondVC). Initially these two views appear in different viewcontrollers. Now, for some reason they have to appear in one viewcontroller and make some changes on one view when some action is done in second view, I need to create another viewcontroller(thirdVC).
Can I just add firstVC.view and secondVC.view on thirdVC's view and create some delegate methods of firstVC and secondVC to be implemented in thirdVC so that I do not need to make changes to existing firstVC and secondVC?

A view controller whose view contains subviews managed by other view controllers is called a "container view controller". This is a supported pattern but you need to see Implementing a Container View Controller and add the child view controllers to their parent container view controller in addition to adding their views as subviews.
This ensures that 1. the parent controller retains the child controllers so that their views do not send messages to deallocated controllers and 2. correctly sends framework messages like rotation events are sent to the child controllers. If you do not use these view controller containment methods your child controllers will eventually break in surprising ways.

Related

Displaying instances of view controllers within Xcode without disturbing the current hierarchy

I am producing an application written in swift in Xcode, I have reached a point in development in which I need to be capable of instancing views. Ideally I would alter the hierarchy of my program to contain a 'Main' or 'Parent' view, the main view would be responsible for displaying the views given to it.
Instancing other view controllers and passing the instance to the main view would be my goal, however, i am inexperienced with Xcode and swift, I am unsure how to go about including a main view without altering my entire storyboard hierarchy.
Here is an image to give a visual description of the current structure.
The intention is to alter the hierarchy to include a main/ parent / master view, the view would be an empty display item which will display all views as and when needed, ideally I would keep the tab control method.
Mainly and most importantly the view will allow instances of view controllers to be displayed, closed and refreshed without impacting other aspects of the app.
Code seems irrelevant here as my views are handled by the storyboard. Something which would be really helpful to me here would be a brief explanation of how I can handle instancing with the new hierarchy.
Thank you in advance for any help regarding this matter
A view controller can serve as a custom parent view controller of one or more child view controllers, displaying their views in any desired manner within its own view's interface.
You can instantiate a view controller in any desired manner. If you wish to pluck a view controller instance out of the storyboard (because you have already designed its view there), call:
https://developer.apple.com/documentation/uikit/uistoryboard/1616214-instantiateviewcontroller
Your view controller in the storyboard will need to have a storyboard ID string so that you can identify it.
After you've plucked a view controller from the storyboard in that way, to display its view in your interface, you must do the following dance:
The parent calls https://developer.apple.com/documentation/uikit/uiviewcontroller/1621394-addchild
The parent captures the view controller's view and sticks it into the interface as a subview of the parent's own view.
The parent calls https://developer.apple.com/documentation/uikit/uiviewcontroller/1621405-didmove
The two view controllers now stand in a legal parent-child relationship and both view controllers will work properly. They can even refer to one another.
If you wish to remove the child view controller's view from the interface, you must reverse the dance:
The parent calls https://developer.apple.com/documentation/uikit/uiviewcontroller/1621381-willmove with a nil parameter
The parent removes the child view controller's view from the interface
The parent calls https://developer.apple.com/documentation/uikit/uiviewcontroller/1621425-removefromparent
Please read "Implementing a Container View Controller" on the main view controller docs page:
https://developer.apple.com/documentation/uikit/uiviewcontroller

Programmatically instantiate custom view controller and getting the subviews by tag

I have three view controllers each under the same custom view controller class, and a page view controller. I want to be able to reuse these three view controllers but with different content on their subviews. However, when I try to instantiate one of these view controllers from the page view controller using [self.storyboard instantiateViewControllerWithIdentifier:identifier], with a method to find the subview by tag right after, the subview returned is null. Is there some way I can get the subview by tag right after instantiating the view controller programmatically?
A view controller's views don't get created until it is about to be displayed. They won't be created after the call to instantiateViewControllerWithIdentifier:
You should put code that accesses the view controllers views in viewDidLoad, viewWillAppear, or viewDidAppear.
You should not try to manipulate a view controller's views from an outside object. That violates the principle of encapsulation, an important principle of object-oriented design. (It also often doesn't work, as you found out.)
If you need do things to the views programmatically you should add one or more public methods to the view controller and call those methods to ask the view controller to make adjustments to its views.

Should Storyboard References work with Container Views?

I just tried it out and it doesn't seem to work, see picture. However, there is error or warning, and since a reference is a view controller - should it be possible?
Setting up a parent/child relationship with a container view is easy.Just create a container view inside the parent ViewController, create the child view controller scene, and then control-drag from the container view to the child view controller to create the embed segue.
If you want to swap the child view controllers depending on some condition, i.e. multiple child view controllers, just create a custom segue. This custom segue is named Empty and is a subclass of UIStoryboardSegue with empty perform method.

Difference between addChildViewController and addSubview?

Both the methods add the view as child of parentview and view can receive events. When to use which one?
It all depends on how you want to manage the new subview. If you want the new subview to be managed by the current view's view controller (e.g. you're adding something simple like a few UILabel objects), you simply call addSubview. If, on the other hand, the new subview has its own view controller (i.e. it's sufficiently complicated collection of views, with rich functionality, that you want to encapsulate all of this complexity with its own controller to manage everything this new subview does) then you call addChildViewController to add the new view controller, but then call addSubview, too.
So, note that addChildViewController, itself, does nothing with the views. You generally immediately follow it with calls that add its view, too, e.g. here is a slightly clarified example from the Implementing a Custom Container View Controller section of the View Controller Programming Guide for iOS:
[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
So, it's not a question of addSubview vs addChildViewController, but rather addSubview vs addChildViewController+addSubview. If you call addChildViewController, you're doing so with the intent of calling addSubview for its view at some point.
Frankly, this question of addSubview vs. addChildViewController+addSubview is rarely how we think about this. A more logical way of thinking of this is determine whether this new view has its own view controller. If it does, you perform the addChildViewController sequence of calls. If not, you just call addSubview.
For a good introduction to view controller containment (e.g. the rationale for that API, the importance of keeping the view hierarchy synchronized with the view controller hierarchy, etc.), see WWDC 2011 video Implementing UIViewController Containment.
They are very different. addChildViewController associates a view controller with a parent container view controller, while addSubview adds a view to the view hierarchy of the view it is being added to. In the former case, the new child view controller will be responsible for handling events when it is the selected view controller of its parent. Think of a tab bar controller--each tab has its own associated "child" view controller that displays its view within the parent tab bar controller's content area and handles any user interaction within that view when its corresponding tab is selected in the tab bar. You should only use addChildViewController when you have a custom container view and want to add a new view controller to its childViewControllers property. If you just want to add a new view to the view hierarchy that can receive events, which is what it kind of sounds like, addSubview is the way to go. "Implementing a Container View Controller" section explains what addChildViewController is for.
addChildViewController is method in UIViewController class and
addSubview is in UIView class
Both have entirely different behavior.
addChildViewController just puts a view controller in front of the current one. You have to manage the flow of controllers. This method is only intended to be called by an implementation of a custom container view controller.
addSubview adds another view as sub view to the view of that object.
Knowing that MVC means Model-View-Controller:
If you only intend to add the view, then use addSubview. e.g. adding a label, button.
However if you intend to a d view + controller then you must use addChildViewController to add its controller and ALSO addSubView to add its view. e.g. adding another viewController, tableViewController.
In addition:
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:
An example of where you would run into an issue if you don't do such is here
For more information I strongly recommend to see answers on this question.
Available from iOS 5, the addChildViewController:
- (void)addChildViewController:(UIViewController *)childController NS_AVAILABLE_IOS(5_0);
method let you add any view controller as a child to some other view controller, but first it removes any parent from the childController and than add it as a child view controller to the specified controller.
The child controller is nothing but an instance of UIViewController and thus it will provide the functionality of view controller (i.e it will receive the events like -(void)viewWillAppear, -(void)viewWillDisappear, etc as a normal UIViewController does).
On the other hand
- (void)addSubview:(UIView *)view;
addSubview: will add any view as subview on any other view.
It's not the choice which to use when rather it's the type which asks to use specific method.
For Instance -
If you have an instance of UIViewController than you will definitely use addChildViewController: (also you can use presentModalViewController, pushViewController) and if you have an instance of UIView than definitely you have to use addSubview.
Note : You can also add view controller's view as a subview to any other view as well.
Based on some test, I found that: If child view controller is not added to parent view controller (supposing the parent view controller is under the root view controller), only child view controller's view is added to parent view controller's view, then:
the sub view controller can still receive messages directly related to view, such as - viewWillAppear:, - viewWillLayoutSubviews, etc.
But
the sub view can not receive some system messages, such as - willRotateToInterfaceOrientation:duration:
I can't give the messages list now, however.
addChildViewController is used to prevent the added sub view controller from releasing, in other word, the parent view controller will hold a strong reference to the sub view controller.

accessing 2 viewControllers

I am creating an ipad application, I two view controllers the size screen of an iphone 5 and I would like to show both of them on the ipad screen, as two distinct UIViewControllers though. Is there a way to do it?
I have tried to alloc the second viewcnotrller in the viewdidload of the first, but what I notice is that it alloc the first and the second, but the first is not accessible any more (it looks just like a still image).
You can do it very easily in the storyboard. Just add 2 container views (next to the regular UIViews in the object list) to your controller's view, and size them how you want. You will automatically get 2 view controllers connected to the container views by an embed segue. Just change the class of these 2 controllers to your custom classes, and you should be good to go. If you need to get a reference to these controllers from the main controller, you can get it from the childViewControllers property. Your main controller (assuming it's the initial controller) and the 2 child controllers will all be instantiated at start up with no code necessary.
Check out view controller containment, in which you have a container view controller, which then can load one or more children view controllers. Also see the relevant section in the View Controller Programming Guide. Also see the WWDC 2011 session, Implementing UIViewController Containment.

Resources