Pass & display the same view from VC1 to VC2 - ios

I have a view (in my case a MGLMapview : mapboxView) which is displayed in my first VC. I want my second VC to display the same view.
So from VC1 to VC2 I did :
self.VC2.mapView = self.mapView
self.navigationController?.pushViewController(self.VC2, animated: true)
Then in the viewDidLoad of VC2 :
view.addSubview(mapView)
My problem is that nothing appears.
However, when I print the size & height of the mapView in second VC, it is not zero.
Do I miss something ?
Thanks for helping

I've asked myself this question too. I don't know if it's possible (I never found a way to do it) but it's not recommended. Once you put a view into a view controller (via addSubview on its view), the view controller "owns" the view.
Here's the UIView documentation that explains why:
Views can be nested inside other views to create view hierarchies, which offer a convenient way to organize related content. Nesting a view creates a parent-child relationship between the child view being nested (known as the subview) and the parent (known as the superview). A parent view may contain any number of subviews but each subview has only one superview.
Instead, add the properties you need to set up a new map view in VC2 (for example center, span, any annotation details) and set up a new map view in the second view controller.

Related

iOS : Why do we need to add child view controller when adding view as subview does the work?

There is a ViewController1 which has a stackView.
I created an instance of ViewController2 and added it's view as a subview to the stackView of ViewController1, I wanted to see if only by doing this does viewDidLoad of ViewController2 is invoked and it did so, ViewController2 viewDidLoad was invoked when I added view of ViewController2 to stackView of ViewController1. For ex: In ViewController1self.stackView.addArrangedSubView(viewControler2.view)
Then why do we need to do addChild(viewController2) then add view as subview, those typical lines which adds childController and it's view in parent view controller hierarchy
Certainly viewDidLoad was called. That happened instantly as soon as you referred to ViewController2's view in your code.
But let's say your ViewController2 does other things besides load a view. Suppose its view contains a button that is hooked through an action to a function in ViewController2. If you now tap that button nothing happens.
That's because the ViewController2 itself is dead: it has vanished in a puff of smoke.
You can see that by implementing deinit in ViewController2. You will see that, just as viewDidLoad is called, so is deinit. You are left with a view controller's view that has no view controller. That is bad.
There is a view controller hierarchy that is responsible for maintaining relations between view controllers. When you add ViewController2 as a child view controller of ViewController1, you maintain that hierarchy, and you maintain it correctly according to the rules, which say:
If VC2's view is somewhere inside VC1's view, then VC2 needs to be a child (at some depth) of VC1.
In other words, the view hierarchy and the view controller hierarchy must run together. Otherwise, the responder chain will break and life will become chaos.
(There are other requirements when you make one view controller the child of another, like sending didMoveToParent to the child as part of the opening dance, along with other message forwarding responsibilities later, so as to ensure that the child view controller gets other messages like viewDidAppear at the right time. It's a complex business. However, I've focussed my answer on the very basic part of what you asked.)
I should add: if your goal was merely to fetch a view out of a nib and stuff it into your own view, you can certainly do that, no problem. What you must not do is use a view controller as a kind of magnet or vacuum cleaner to fetch a view for you if your intention is then to let go of the view controller itself.

IOS difference between subview and container view

what is the difference between a subview and a container view. I have a piece of code that is successfully working by adding subview programmatically. But I want to be able to lay out the subview in the editor not in code. The only thing I could find was containerview. What is the difference and can they be used interchangeably.
Thanks.
You use UIView when you already have a view and you do not need to have a dedicated view controller to build and handle interactions within it.
From the UIView help page:
UIView object claims a rectangular region of its enclosing superview (its parent in the view hierarchy) and is responsible for all drawing in that region ...
Simplified structure: YourViewController ---(has)---> UIView
You use UIContainerView when you need to embed another view controller in the one that you already have. The embedded view controller is in charge of returning a view for the region that the UIViewContainer occupies. Therefore, your UIContainerView knows which view controller to use to render UIView inside the region it occupies.
From the UIContainerView help page:
Container View defines a region within a view controller's view subgraph that can include a child view controller.
Simplified structure: YourViewController ---(has)---> SubViewContoller
---(has)---> UIView
That SubViewController returns a view and handles its events.
Last if you want to learn how to layout subviews, i cannot explain that over here, so you might need to go through one of the tutorials.
https://www.raywenderlich.com/113388/storyboards-tutorial-in-ios-9-part-1

Getting a VC to appear inside another VC

I have 2 ViewControllers.
VC1 has a 2 views inside it.
I want to get MenuUIVC to appear in one of my views belonging(child) to VC1.
I tried this code inside of VC1 but it didn't work.
MenuUIVC * menuViewVC = [[MenuUIVC alloc] init];
menuUIView = menuViewVC.view;
I expected to be able to see the MenuUIVC inside the view (menuUIView) which is a child of VC1. I have the IBOutlets all hooked up on the storyboard.
You can use Container views to get View Controller inside a View Controller. And, you can get the reference to it through prepareForSegue() method.
Links for description:
iOS Container View
The Easy Way to Switch Container Views in iOS
If you are using UIView, then why don't you use
[menuUIView addSubview:menuViewVC.view];
Another option is to use childviewcontrollers.
See these links for example:-
adding view controller as child view in ios
Add child view controller to current view controller
Using container or child view controller, gives you full fledge option of using View Controller properties, which you will not get in UIView.
Say for example, you can you orientation delegate methods, which you can't using in UIView class directly.
Hope this can help you.
Cheers
Sanjay
you can go for container view if you want to do it using IBOutlets & storyborad.
but if you want to do it using code then follow the below steps :
initialise & create parent view controller.
then add required child view as a subview with negative frame.
now change the frame with UIView animation whenever required. & do add tap gesture recogniser on part of screen other than the child view to remove it back to the initial position.

What is the difference between a UIView outlet, and a ChildViewController?

Lets say I have a container view in a parent UIView.
What is the difference between referencing it as an Outlet in my parent UIView, or accessing it this way :
categoryContainerViewController = self.childViewControllers[0] as! CategoriesControllerView
View and view controllers are two different things
A VIEW is an object that is drawn to the screen. It may also contain other views (subviews) that are inside it and move with it. Views can get touch events and change their visual state in response. Views are dumb, and do not know about the structure of your application, and are simply told to display themselves in some state.
A VIEW CONTROLLER is not drawable to the screen directly, it manages a group of view objects. View controllers usually have a single view with many subviews. The view controller manages the state of these views. A view controller is smart, and has knowledge of your application's inner workings. It tells the dumb view objects what to do and how to show themselves.
now you can get idea about View and a view controller.
A view and a view controller are two totally different things.
categoryContainerViewController = self.childViewControllers[0] as! CategoriesControllerView
In spite of the name, that is a view controller.
The outlet is to the view.
In layman terms : -
IBOutlet connects any view element from your interface builder to attached swift class file. So you can get reference to any subview of UIView(eg, UILabel, UIButton) from interface builder to your UIViewController or UIView Swift class
In your ex.
by using
categoryContainerViewController = self.childViewControllers[0] as! CategoriesControllerView
You are getting reference to your ChildViewController and not any view

Set View Controller Subview Loaded from Storyboard

I have a custom view controller I load from a Storyboard. When I try to set one of its subviews nothing happens (remains generic white view). What I don't understand is if I try to set VC.view it works fine. Why is this? Everything seems to be initialized after I load from the Storyboard. Where would I set the VS's subview?
Yes, this slightly confusing behaviour is how it is 'supposed' to work. When a view controller is loaded, its view is not - at least not until it is actually needed. See this doc for further info. Only when the view controller is presented, will it then load the view. As you have found, this is tiresome, because you often want to set some of the the subviews' properties before it is presented (say in a prepareForSegue or prior to pushViewController: or presentViewController:).
There is a work around - based on what you have observed. If you directly access the view property, the view controller will immediately load the view and all its subviews. So, if you want to set subview properties, just "touch" the view itself:
NSLog(#"View tag is %i", viewController.view.tag);
and you should then be able to access the subviews.
Alternatively, you could pass the relevant data in (non-UI) properties of your view controller, and then set up the subviews using that data during viewDidLoad or viewWillAppear.

Resources