I have a UITableViewController and in the didSelectRowAtIndexPath method I create an instance of a UIViewController and push it on to the stack.
The UIViewController is meant to edit the content of the selected cell but how do I get the changes made in the ViewController transfered back to the TableViewController?
Cheers
The standard way to pass data back up the hierarchy is with delegation or even more simply through querying a property on the edit view controller when you want to get the edited data back.
Now, when it comes to edit view controllers you can design them to support both direct editing of 'live' objects, or a copy which will let you do a Save/Cancel model.
So what you want is for your edit view controller to edit some sort of ModelObject instance with various properties. These properties will correspond to the textfields or date-pickers etc. in the view. So you might have a Person with NSDate *dateOfBirth and NSString *name.
When you create the view controller and push it onto the navigation controller, you give it one of these ModelObjects to edit. You can either pass in an object straight from your model which will be edited 'live' as the user enters values, or a copy which will let you discard changes and implement a Save or Cancel workflow. For the latter you can add the Save and Cancel buttons yourself before you push the edit view which lets you handle the actions yourself without needing delegation.
So your edit view controller will set the properties on this object when the user enters a new value in a textfield or changes the date picker. For a live object these changes will be applied immediately to your model. For a copy, when the user hits Save you query the edit view controller for the object you passed in and merge/copy that back into your model. If the user hits cancel, you just discard the object.
Override the "parent" or table view controller's -viewWillAppear: method and reload the table view data there, using [tableView reloadData];.
When you go back to the table view controller from the edit view controller, the table view controller's -viewWillAppear: method reloads the data, which in turn calls the table view delegate methods.
You have to make sure that the two controllers 'share' data somehow. The easiest option is to have the first controller pass in the array (or just the selected object) that is selected in the table. The second view would then directly modify that array (or single object) and then when you dismiss the second view will show the modified data.
You might have to reload the table.
Makes sense?
Related
I am trying to create a simple app and here is how it works:
When the user clicks the button "Picking", it'll show a tableview. And when the user selects a row in the table view, it will show the first view and display the data on the label.
I have 2 problems:
Every time I click the button "Picking", a new instance of the table view controller gets created; but does not reuse the existing one. How can I make it reuse the old one?
I want to pass the selected data to the root view. I tried by creating a segue to show the root view when user selects a cell and then passing the data on prepareForSegue method. But, I faced the above problem of memory leak. How do I pass the data between screens without leaking memory?
It sounds like you may be making a circular view hierarchy. When you tap on the cell in the table view, if you're pushing a new instance of the first VC, that is the wrong way to do it IMO.
Instead, you should pass the data back to the first VC then dismiss the second VC. Then, when you tap on the "Picking" button again, it's a new instance of the table view but your previous instance has already been removed from memory.
This allows for the smallest amount of memory to be used at any given time. When the table view controller isn't on the screen, it doesn't need to be in memory.
IMO, the best way to pass data up a navigation stack is to use a protocol and delegate. It's similar to how Objective-C protocols and delegates worked if you're familiar with that. Here is Apple's documentation on both. The delegate section is about 1/3 the way down the page.
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html
I'm looking after a solution to prevent object release in storyboard views.
Here is the deal, I have a storyboard view which contains data grabbed from JSON. This view has relation with another view (First View:List of items -- Second View:Item Details). Now when I tap on an item in first view, it goes to another view and shows the detail (using segue). BUT when I go back to the first view, it needs to grab the data from JSON again. (makes the user angry)
I'm aware of using Tab template, but I can't due to the application user requirements.
I'll be so much appreciated if anybody could help me.
Gratitude.
You are incorrectly implementing the Model-View-Controller pattern. Views should never fetch or hold data. They simply display it. View Controllers also do not hold data. Views and view controllers can be thrown away any time they're not on screen. This is by design.
Create a model class that is responsible for talking to the server and holding the resulting data. The controller should hand the model to the view, and the view should just display what it finds in the model.
I think you need to do a modal Segue from your First View to the Second View. Then when you are finished with the Second View execute [self dismissModalViewControllerAnimated:YES]; in the Second View to dismiss the Second View and return to the First View. This should then display the First View once more with the data.
i have a view(page) with lots of textfields,date pickers, etc. This page is displayed using presentModalViewController. Now i want to save the data entered in the textfields to the tableView. Each textfields in the page corresponds to the column in the tableview.
I want to save the page's data on click of a button to the tableview as row wise.
Any Help !!
You could use a protocol and delegate object. Here is a simple example that will show you how to accomplish that:
http://www.theappcodeblog.com/2011/04/15/passing-data-between-views-tutorial-using-a-protocol-delegate-in-your-iphone-app/
Your View is presented from a ViewController, which is Controlling the View.
On clicking the save button on the View, the ViewController can pull the data from the fields in the View, and save them into a Model object which you can then add into your UITableViewDataSource array (or whatever you have to load data into your table).
You can then tell your UITableView to update row at index path, and it will pull the new data from the datasource and update your table.
Voila....
... a cleverer (is that a word) approach would be to bind your Model properties to your View elements (from your controller), so as they are updated, the model changes. The table could be using KVO to listen for Model changes and update their view components at the same time.
Sort of a simple question. I have a tableview in a navigationcontroller. When I touch a cell, it pushes a view controller with the information from the cell, so I can edit it in the new view. Now thats working correct (we can call it the informationpath: "rootviewcontroller -> pushed viewcontroller"). But when I click save in the new view, I want the edited values to travel back to the rootviewcontroller before I call popviewcontroller (informationpath: "pushed viewcontroller -> rootviewcontroller"), so the edited values can be displayed in the tableview.
Whats the correct approach to this?
EDIT:
pushViewController and popViewController is working. I only asked for the best approach to get the edited information back to the rootViewController for display in the tableview, when Save-button (popViewController) was called. I guess I'll just have to edit the pList with the new information directly from the pushed viewController. Though I would prefer sending the new information to the rootViewController and have it handle the access to the pList-file.
I have the same situation - two tableviews. The first TV displays a list of database records and when one is tapped it goes through to the second TableView which displays the details of the record. I do this by pushing the details TableViewController onto the navigation controllers stack. So far so go and quite simple.
The problem I encountered was that after updating the record in the details table view (controller), I wanted to let the list table view controller know, so that it could update the list of records.
The first thing I did was to add a property to the details table view controller so that when a row was selected on the list of records, the list controller could pass the core data managed entity to the details controller.
At the same time, I also added the list controller as a observer of core data change events like this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(dataSaved:) name:NSManagedObjectContextDidSaveNotification object:nil];
So if the details table view and controller update the record, the list controller has it's dataSaved: method called, passing a NSNotification object.
In the dataSaved: method I examine the object and if the core data entity being edited is in the updated list, then I set a flag to signal an update is required. However if there is a record in the inserted list, it means that a new record has been created and inserted into the database, so a flag is set to trigger a full reload of the list table view.
When the user returns to the list view controller, the viewDidAppear: method is triggered. In this method I examine the flags and either call
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
to reload the specific record if the record was updated, or tell the table view to do a full reload if there is an insert of a new record.
Finally I then remove the list controller as an observer of core data notifications because it is no longer interested.
I don't know if this is the recommended way to do this, but so far it's working for me.
You can try to reloadData before popViewController but you should post some code.
All UIViewControllers have a navigationController method. When you push a view controller to a navigation controller, that property is set to point to the navigation controller.
So, just call [self.navigationController popViewControllerAnimated:YES]; in the view controller.
Also, don't confuse views and view controllers. When you click save in the view, you should make sure that the save button calls a method on your view controller, which in turn talks to the navigation controller.
On tapping a row You are going to new view with appropriate information.
Here you perform some operation such as editing data.
So first save the changes on click on save button (By calling an IBAction) and in this IBAction method will check wheter (changes are successfully saved) then call
[self.navigationController popViewControllerAnimated:YES];
And ensure that table reload itself by updated databese (for this change array of data by calling database method in viewWillAppear method).
I've got a view controller, call it VC1, that's a table view. When I tap a cell in the table view, I am presented with a new view controller, call it VC2, which is a short list of choices. After making a choice, I want to dismiss VC2 and set the cell.textLabel.text property of the VC1 cell I originally tapped to the value I selected in VC2.
Conceptually speaking, what is the proper way to do this? I've tried a handful of different approaches, but all of them seem wonky at best, and only one of them actually worked - although it was the most cumbersome of all, passing references to both view controllers and table view cells and all kinds of things. It just feels like I'm making a mountain out of what is probably a mole hill.
This is such a common paradigm that I find it hard to believe there's not a simple method for doing it.
There are a number of ways to handle this but one of the most flexible is via the Delegate Pattern. Define a delegate protocol in VC2's interface and then make VC1 conform to that protocol. When you create VC2 assign VC1 as it's delegate (similar to the way you did with your UITableView). One requirement of your protocol should be a method like didFinishWithStringSelection: (or whatever you call it) where you would update the table cell and reloadTable.
I do kind of that with with a table view presenting several attributes of an data object. To change a single attribute the user has to select the specific table cell showing the attribute he wants to change and that will push a new view controller (with a picker in my case) where the user can change the value from a selection.
I assign the data object to a property of the new controller before pushing. With this the value can be changed directly in the data object, and when i return (via navigation controller) to the first view controller there is a reloadData in viewWillAppear.
Did you try it this way?