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).
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 have place this question before on following link with code & screenshot.
TableView is not loading data?
Now I came to know my tableview is loading data in tableview cell but not showing/displaying it. I have one Model View Controller in my project. The ModelView controller get called from Mapviewcontroller screen through Search Button. After resigning the Model view controller I can see the data in tableview. (It means when I move to next controller and back to previous tableview.. my tableview shows data in it.)
Here I my data get visible in tableview only after resigning the modelview controller.....
Everything works fine. I just want to know how should I display the tableview data as soon as web-service get called on first screen itself???
Put [_tableView reloadData]; at the end of the method that calls the web-service, or the one that populates the markers array.
If you are manipulating table data in an asynchronous Block,
pass a reference of the tableview to the method implementing the block, and remember to call
[tableview reloadData];
within the block, and not out outside
I'm trying to get a better understanding of the UINavigationController. I have 3 .xibs. From .xib1 I am pushing to .xib2. I have to pass data to .xib2 from .xib1.
Controller1 *selectcity = [[Controller1 alloc]initWithNibName:#"Controller1" bundle:nil];
selectcity.item1 = #"hi";
// Push the next view onto our stack
[self.navigationController pushViewController:selectcity animated:YES];
[selectcity release];
I need to pass some data to .xib2 every time it opens that view. Pushing a new view onto the stack every time the user selects a row in the table, and then pressing back, selecting a row, back, selecting a row, back is creating a memoryWarning very quickly and killing the app.
If I add the view as a property and check if it already exists,
if (xib2 == nil) {
}
the viewDidLoad method only gets called the first time the view is called so I can't pass my data to the form.
I can't use viewDidAppear etc. because I don't want to the data to load when coming back from .xib3.
What is the correct way to control memory in this situation? Should I be popping xib2 from the stack every time they press the back button? Is so, what method would I do this?
Thanks for any help!
I'm trying to get a better
understanding of the
UINavigationController. I have 3
.xibs. From .xib1 I am pushing to
.xib2. I have to pass data to .xib2
from .xib1.
First off, you don't pass data between .xibs, you pass data between view controllers.
I need to pass some data to .xib2
every time it opens that view. Pushing
a new view onto the stack every time
the user selects a row in the table,
and then pressing back, selecting a
row, back, selecting a row, back is
creating a memoryWarning very quickly
and killing the app.
Please post more of the code related to this problem. Assuming you're talking about UITableView rows, your app shouldn't have any problems pushing/popping views onto the navigation stack in response to taps on rows.
the viewDidLoad method only gets
called the first time the view is
called so I can't pass my data to the
form.
Again, you want to pass data between view controllers, not views. You can do this quite easily by creating properties on your view controllers that you then set before you push the view controller on the stack. You are already doing this, I think with your item1 property.
What is the correct way to control
memory in this situation? Should I be
popping xib2 from the stack every time
they press the back button? Is so,
what method would I do this?
If you're using a standard UINavigationController to control the navigation stack, you don't need to do anything on your own to manage memory when the user hits the back button; the UINavigationController class will take care of releasing view controllers itself.
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?
I'm pretty new to iPhone development and have struggled to find what I consider to be a neat way around this problem.
I have a user interface where a summary of record data is displayed in a table inside a navigation controller. When the user clicks the accessory button for a row, a new view is pushed onto the navigation controller revealing a view where the user can edit the data in the corresponding record. Once done, the editing view is popped from the navigation controller's stack and the user is returned to the table view.
My problem is that when the user returns to the table view, the table still shows the state of the data before the record was edited. I must therefore reload the table data to show the changes.
It doesn't seem possible to reload the table data before it is displayed as the call only updates displayed records. Reloading it after the table has been displayed results in the old data changing before the user's eyes, which I'm not too happy with.
This seems to me like a pretty normal thing to want to do in an iPhone app.
Can anyone please suggest the best practice approach to doing this? I feel like I'm missing something.
Cheers - Steve.
The standard approach may sound like a lot of hassle at first, but is a useful pattern for a lot of situations.
In your tableview class create a method like:
-(void)editDone {
[self.tableView reloadData];
}
Add a property to your edit controller like:
#property (assign) id delegate;
Set the delegate when your accessory is clicked:
editController.delegate = self;
And when editing is complete, call your method like so:
[delegate performSelector:#selector(editDone) withObject:nil];
You can create similar methods to handle cancel of your edit component, or to carry out dismissing of modal edit controllers, etc. It's considered more classy to put all this in a protocol, if you like.
I'd implement this in the following way:
Save indexPath of a clicked cell.
Implement -[UIViewController viewWillAppear:] method of the view controller, which contains the UITableView. If saved indexPath is not nil, reload specified cells with:
-[UITableView reloadRowsAtIndexPaths:withRowAnimation:]