Accessing View Objects In Container View - ios

I have a UIViewController (1).
Within this UIViewController I have a Container View (2).
In the Container View's (2) UIViewController (3) I have a UILabel.
How do I access the label text property from The first UIViewController(1)?
My UIStoryboard looks like this:

What you likely want to do is create a reference to the child view controller in the parent view controller, and access the label property through the child view controller.
Generally, however, you don't want to have a parent object directly control a child object's elements. In essence, you want the responsibility of managing the UILabel, and its contents, to fall on whichever view controller owns it. So I would recommend designing the app logic in such a way that the child view controller totally manages its own objects.
For example, instead of simply giving public access to the UILabel on your child view controller, you could create a method like - (void)UpdateYourLabelWithText:(NSString *)text; that would then make updates internally. This separates your view control logic and delegates responsibility to the correct view controller.

Implement prepareForSegue. It will be called when view controller (1) is instantiated. You can assign the segue.destinationViewController (which is view controller (3)) to a property at that time, and then you can access any of its properties.

Related

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.

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.

Objective C : change label with segue variable between two views with same controller

I have a main view controller that processes data. I want to send this data and display it in a modal view without using another controller.
I have something like this in my controller:
NSString *myData = #"something";
[self performSegueWithIdentifier:#"MySegue" sender:myData];
I have created a new view in the storyboard and a "Present modally" segue between them. I have created a label in the new view that I would like to change to display the content of myData.
But since there is no controller for this view I can't find a way to link the label to the data. Every advice I find (like PrepareForSegue) is for a two controllers configuration.
Every scene (at least every scene that you want to update custom controls on) should have its own view controller. If you create a scene without a custom view controller class specified, it will still instantiate a standard UIViewController object. Without a custom view controller, you have no way of updating the label on that destination scene.
The standard answer applies here. Give that destination scene its own view controller class, define a custom property in that destination class, have prepareForSegue in the source controller update that custom property in the destination controller, and have the destination view controller's viewDidLoad update the label on the basis of that custom property you set.

Passing a variable from modal tableview to parent view

I have a detailView which has a button on it to bring up a tableView as a modal view to help the user giving a selection of names. I'm trying to figure out a simple way of passing the selected name to a textField on the parent detailView.
I have been building this project using Storyboard, but I am totally stuck at this point.
There are several ways to approach this kind of problem:
shared object: The parent view controller provides some object to the child that contains the state that the child is expected to work with and possibly modify. In this case, it might be a dictionary that contains an array of names to display and the index of the selected person.
child's properties: Often, the child view controller itself is the shared object. The parent instantiates the child, sets some of the child's properties (e.g. people and selectedPerson), and presents it. When the child is finished, the parent gets the properties of the child that it cares about (e.g. selectedPerson) before releasing it.
delegation: Sometimes the child view controller will need to interact with the parent in order to do its job. This is a good time to use delegation: establish some protocol that the child knows about and the parent implements, add a delegate property to the child, and have the parent set the child's delegate property to itself before presenting it. This way, the child can talk to the parent without depending on the parent class.
For the case you describe, where you just want to convey some piece of data back to the parent when the child is done, the second strategy above is the simplest.
Note: DetailViewController below should be replaced with whatever the class is of your detail view controller.
1) If you don't already have a subclass of UITableViewController, create one. This will allow you to add a property to the table view controller. Change the class of your modally presented controller in your Storyboard to this new subclass.
2) Add a property to your table view controller subclass like this:
#property (weak, nonatomic) id mydelegate;
3) In prepareForSegue in your DetailViewController, set the mydelegate property of the destination view controller to self which is a pointer to your parent detailView.
4) In your DetailViewController, create a method to receive the selected name:
- (void)userDidSelectName:(NSString *)name;
5) In the tableView:didSelectRowAtIndexPath method of your tableViewController subclass, get the name from the tableViewCell and call the userDidSelectName method on the delegate:
[self.mydelegate userDidSelectName:selectedName];
6) The correct way to to this would be to define a protocol that has a method userDidSelectName and then make the delegate pointer in step 2 require a class that implements that protocol. The quicker and dirtier thing to do is to make the delegate pointer in step 2 of type DetailViewController * instead of id. This will allow you to call userDidSelectName without the compiler complaining.

In ios 6, how do you use pass data between View controller holding 'Container View' object and Table View controller that is embedded in it?

I have a view controller with a label and textfield. I also added a container view which points to another table view controller with one section and 3 rows, basically static table view. I am unable to find any documentation / example which tells you how you pass data between View controller holding the Container View and Table View container embedded in the container view. I want both sided communication ?
The controller embedded in the container view (in storyboard), is automatically added as a childViewController of the controller in which the container view is added. Just to make sense of what I mean, add this line, in your viewDidLoad method of the base controller :
NSLog(#"children : %#", self.childViewControllers);
So lets say in VC1, you add a container view with an embedded controller VC2 (your tableViewController), then the above statement will log VC2 as a child of VC1. To access VC2 from VC1, you just use [self.childViewControllers objectAtIndex:0], and to access VC1 from VC2, just use self.parentViewController.
Hope this helps
If you set things up in a storyboard, you use segues. Just like most everything else in storyboards.
See Access Container View Controller from Parent iOS
There are new properties on UIViewController -childViewControllers and -parentViewController. You could use those.
Alternatively you could set up a relationship yourself. Be weary of retain cycles. Perhaps the parent owns the child and the child has a weak reference back to the parent.
[self.childViewControllers lastOject] or [self.childViewControllers objectAtIndex:index]; , depending upon how many child VC's you have.

Resources