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.
Related
There is ViewController which contains elements such as
UIPickerView and two UITextFields.
There is PickerViewController, where UIPickerViewDelegate and UIPickerViewDataSource methods are implemented (didSelectRow, titleForRow, and the other ones).
After an element is selected in the UIPickerView, I need to change the text of one of the UITextFields. I can't do that, because didSelectRow: is implemented in PickerViewController but UITextField is contained in ViewController. How can I get access? And most importantly, how can I do that correctly?
Should I implement the picker methods in another class, or have them in ViewController?
how can I do that correctly?
This is a better question than simply how to let the PickerViewController change a text field in its parent view controller, because really it shouldn't.
Two possibilities spring to mind: the picker controller can pass some kind of message directly back to the other controller, or it can update a model, which the other controller reads from after the picker view is done.
The first is probably most easily accomplished by giving the picker controller an "after picking" handler Block that would have the necessary data as an argument, and that the parent controller defines and sets on the other. Before the picker controller is dismissed, it should call the Block, passing in the selection and performing whatever actions the other controller specified.
The second means that the parent controller and the picker controller must have access to the same data object. Without knowing what else is going on, it's hard to be exact, but one good possibility is that the parent controller actually gives the picker controller the model object that it should read from, rather than the picker controller acquiring it on its own. The picker controller just changes the object that it's passed.
You can add a UITextField properties to a PickerViewController and pass UITexiField instances from UIViewController:
in PickerViewController.h:
#property UITextField *textField1, *textField2;
in UIViewController.m:
PickerViewController *picker = [PickerViewController new];
picker.textField1 = self.textField1;
picker.textField2 = self.textField2;
You can implement PickerView anyway - in another class or in ViewController.
you can use custom delegate to update the textfield values.
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.
I have several View Controllers, all using a UITableView, with identical custom cells. The UITableView Datasource methods are identical too (to the line); all that changes is the data source itself (the array from which the table view is loaded). It seems rather redundant for me to have to copy the exact same code for 5 such View Controllers (not to mention it's a bad coding practice!).
I therefore thought of creating a base (or parent) view controller that extends UIViewController, and have all my following (child) controllers inherit from this base view controller.
My problem is this: My base view controller needs to have a UITableView property, and it also contains the DataSource methods. I cannot get the UITableViews within the child view controllers to refer to the parent class for their DataSource.
Am I on a completely wrong track? Is there a better approach to this problem? Any help is greatly appreciated!
Just have one controller into which you add a property for the data source.
When you segue to the controller or create it set the data source property.
If all the code is identical except the data source array, you only need one controller.
In xcode add a new source file: e.g. MyDataViewerController which inherits UITableViewController.
In that file when created, add a property of the form:
#property NSArray *dataSource;
Click on one of your view controllers in storyboard and click the Class attribute inspector tab. Set the class to MyDataViewerController.
You can now use this controller to show any of your data. You can probably delete all the others.
I've assumed its an array containing the data. Replace this with whatever you use.
Assuming you segue to this controller from somewhere, set the property in the
prepareForSegue function.
Is there any way that could send the value in Class of ViewController to Class of View?
Because I want to make a drawing board and I made a modal scene to set values about color, width .
I know how to send the value in modal scene to my ViewController , but now I need use those value in Class of View , or not Class of ViewController.
Sounds like you need to devise a protocol to open a delegation channel between the two classes. Then when the modal VC wants to send data to its delegate (its presenter, in this case), it can of its own volition.
The View Controller can have a reference to the View, therefore the View Controller can simply pass the values to View by calling a View's method or updating View's properties. This is a common pattern: View defines a Protocol and data/requests from View to ViewController go through this Protocol (the ViewController acts as delegate of View); and ViewController owns the View.
For inspiration on how to implement a farily decoupled design applying this pattern, you can have a look at documentation on UICollectionView and UICollectionViewController.
Other options, depending on what design you need, are Key-Value Observing or Notifications.
I have a UITableviewController and I push another UIViewController in 'didSelectRow..' method.
I have user input controls (combobox, stepper) in this viewController, that when the UIViewController is popped , I would like to receive the newly entered data in the UITableviewController (and update the tableview accordingly).
I saw some questions/answers, and some said to use "Delegation/Protocol" approach, but did not find any specific example how to achieve this.
Can someone help?
Create a new file for your project and choose the Protocol file type. (We'll call it CallBackProtocol.) In the view controller that you push, create a property that has a type of id<CallBackProtocol> delegate;. Have your table controller adopt the protocol and, when it creates the view controller, set controller.delegate = self;.
Define a method in the protocol that lets you pass whatever data you need back to the caller. Implement that method in the table controller and call it from the second view controller just before popping it.
(Or use a NSNotification.)