Force tableView reloadData from Modal Dismissal? - ios

When my application launches, a table view is present and uses the information in two arrays (countdowns and countdown_info) to populate the cell title and description in the table view respectively.
A modal can be opened and used to create a new countdown. So far, it saves the data in a local file, closes, and then returns to the front controller, but the table is not updated with the new data.
How can I get the new information added to the table? The UITableView is named as *countdown_table
Thanks!
EDIT: The return code looks like this:
...Above Saves the File...
// The following generates a warning. ClockworkViewController is the main view controller.
//[[ClockworkViewController countdown_table] reloadData];
[[self parentViewController] dismissModalViewControllerAnimated:YES];

Load the newly added value to the array
Call [tableview reloadData] in your table view controller's viewWillAppear method.

Are you calling the [yourTableView reloadData] function? You should call this either when the modal view is saved, or when the table view becomes active again. This will then check all of the tableView's methods for number of rows, number of sections, etc, and reload the entire table.

You may explicitly call [table reloadData] when you dismiss the modal view

If you're using Interface Builder to perform your presentations/dismissals, you can very easily reload the ParentVC's tableView from the ModalVC's Exit Segue (transitioning back to the ParentVC, of course).
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"YourDismmssSegueID"]) {
ParentVC *vc = segue.destinationViewController;
// perform any needed data manipulation here
[vc.tableView reloadData];
}
}

Related

Setting tableViewCell in a container from a parent view controller

I'm trying to make a very basic settings app where a user sets 5 options on a UIViewController and then performs a function based on the selected options. 3 of the options are in a container which contains a UITableView. When a cell from the table view is selected, a new view controller is shown with options for that cell (i.e. user selects "Metal" from the table, and then "Steel" from a new detail view controller). When a value is selected, the UIViewContoller/parent view is shown using an unwind segue and the detail text for the "Metal" row should display "Steel" in the container table
The cell selection segue works appropriately, and NSLog shows that the option selected is being stored correctly. The issue is that I can't figure out how to set the detail text label to the newly set variable. What code do I need to set detail text labels on the container table from the UIViewController?
A little additional info: my unwind segue goes back two view controllers. If I unwind to the table inside the container, the segue doesn't work on row selection.
Here's the prepareForSegue code from settings selection (the view controller that shows "Steel" from my example)
//Sets selected metal on row selection
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender: (UITableViewCell *)sender {
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:selectedIndexPath];
self.selectedMetal = cell.textlabel.text;
NSLog (#"%#", self.selectedMetal);
}
This is the code for my unwind segue and is executed once a detail row is selected:
-(IBAction) unwindToParentView:(UIStoryBoardSegue *)segue{
MetalTableViewController *child = (MetalTableViewController *) segue.sourceViewController;
//Trying to reference the container table here
OptionTableViewController *optionTable = [[OptionTableViewController alloc] initWithNibName:#"OptionTableViewController bundle:nil];
//Have a table view cell in the .h set as an IBOutlet that I'm trying to set here
optionTable.cell1.detailTextLabel.text = child.selectedMetal;
Update
The issue definitely has something to do with the new instance of OptionTableViewController that I'm creating. I can manually set the value of the the detailTextLabel for my container table view controller in its viewDidLoad method, but when I try to NSLog the value for optionTable.detailTextLabel.text it returns a (null) value which means I've got something wonky in my unwind block or I'm not passing the selectedMetal variable correctly.
To fix this issue, I changed my initial design a little and put all of my options in a table view controller. Now my segues work correctly and I'm not having any issues passing data between controllers. If anyone can propose a solution for the original issue (passing data from a parent view to it's embedded container view), I'll gladly give it a try and upvote the answer if it works.

iOS TableView Reload after dismissing modal

In my app, I am listing core data entries in a tableview. I want to allow the user to edit records using a detail view presented modally as a form view. I am observing peculiar behavior when editing records.
The flow:
User loads tableview with records. -working
User selects a record for editing. -working
User edits record in a view controller presented as a modal form view. -working
User saves edits and dismisses form view. -working
Tableview shows correct changes for the previously edited record. -working
User repeats steps 2 - 4 selecting a different record to edit. -working
Tableview shows correct data for all records. -Not Working.
At step 7, the tableview reverts the display of the first edited record to its original state. Subsequent record edits result in all previous edits reverting to their original state. If the tableview is dismissed and reloaded, the records are correct, showing all the edits.
I have used [tableview reload] in the tableview's ViewWillAppear method, but it does not seem to be fired when the modal form view controller is dismissed.
In my tableviewcontroller code:
-(void)viewWillAppear:(BOOL)animated
{
[self.tableView reloadData];
}
Searching around, I have not found a solution and am hoping someone can point me in the right direction.
Thanks!
When you presenting a modal view, main view controller's view never disappears. So, after you dismiss your modal view, viewWillAppear() won't be called.
You could try to implement a custom delegate function in your modal view, and set it in the main view controller, when your data is updated, fire the delegate function to reload your tableView, which is at your main viewController.
Understand what is delegate function in iOS, and
how to create a delegate function is like this:
In your ModalView.h:
// define the protocol for the delegate
#protocol ModelViewDelegate <NSObject>
- (void) didUpdateData;
#end
#interface ModalView: ViewController {
//create a delegate instance
id delegate;
}
// define delegate instance
#property (nonatomic, assign) id <ModelViewDelegate> delegate;
In your modalView.m:
#synthesize delegate;
and then inside your function, put the delegate function at place where you need to fire, for example:
- (void) updateDataIntoDatabase{
....
//Update work done.
[self.delegate didUpdateData];
//dismiss your modalView;
}
So, in your MainViewController.h,
#import ModalView.h
and
#interface ModalView: ViewController <ModelViewDelegate > {
...
}
Inside your MainViewController.m, you will get a warning saying that you need to implement the delegate function which you already declared. So, set the delegate function, and do the things that you like to do:
- (void) didUpdateData{
[self.tableView reloadData];
}
DON'T forget to set your modelView delegate to self after you instantiate the modalView instance. If not your delegate function won't be fired.
modalView.delegate = self;
Use completion block when you trigger the Modal viewcontroller:
-(void)editModal:(id)sender
{
KDSecondViewController *secondVC = [[KDSecondViewController alloc] init];
[self presentViewController:secondVC animated:YES completion:^{
//-- reload your table view when user dismiss the modal view
[self.tableView reloadData];
}];
}

How to load specific row in table and then view controller based on a button press

I swear I saw something about this in the documentation but can't find it (as I'm not sure what to look for).
Basically in my app, the first VC consists of a map where users can select annotations and a callout button on each one. Otherwise, the user can also select a button that'll open a searchable table of the buildings on the map and load view controllers displaying the details (basically a master-detail setup).
What I want to do is for the callout to load a specified path for that particular building. So if I tap the callout on building A, it opens the detail view controller to show the information.
How do I do this, or what piece of documentation will help?
From reading this, it sounds like the map view an the table view belong to the same view controller. If so, then the view controller is where to want to centralize things. Again assuming the model is an array of data objects, have a method in the controller that does all the work of coordinating the different views.
- (void)selectModelAtIndex:(NSUInteger)index sender:(id)sender
{
if (self.isSelectingModel)
return;
self.isSelectingModel = YES; // Stops recursive calls to -selectModelAtIndex:
NSIndexPath *indexPath = [self indexPathForModelAtIndex:index];
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone;
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNon animate:NO];
MKAnnotation *annotation = [self annotationForModelAtIndex:index];
[self.mapView selectAnnotation:av.annotation animated:NO];
[self performSegueWithIdentifier:#"Identifier Of Detail View" sender:sender];
self.isSelectingModel = NO;
}
This is a single method which keeps the tableView and the mapView in sync before segueing to the details view controller. You need to have a isSelectingModel property, -indexPathForModelAtIndex:, and -annotationForModelAtIndex:.
This method is called by the table view and map view did select callbacks.

Conditional Segue navigation from UITableViewCell based on response to UIAlertView

My problem seems like a generic problem, yet can't seem to find an answer for it.
I have a situation where when the user taps on a custom UITableViewCell, I would like to display an alert and then based on the response to the alert, either stay on the same view (user selecting cancel) or display another view (if the user selects proceed). And I would like to do this using the storyboard feature & segues.
How would one go about this? Do you have to do this the old fashioned way?
#user, Just create the alertView the old fashion way; I do know of any storyboard feature to do this differently. Where storyboard can help is with the segues. You can call the segues programmatically. With you alert view cancel button you can just return (i.e. do nothing). For the other option, to display another view, you can programmatically call a segue to transition to the desired view. If you don't have the proper segue already defined for some other reason on your storyboard, just create a button out and use that to create the segue and name it. Name the segue by clicking on it in storyboard and use the attributes inspector to give it name (identifier). Then hide the button or put it out of the view. I typically put these type of button on the toolbar and use spacers to keep them out of the view. Here's some sample code:
Call the segue from the alert view delegate like this:
[self performSegueWithIdentifier: #"done" sender: self];
Also implement this method to do any necessary task to prepare for the segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"done"])
{
// [[segue destinationViewController] setManagedObjectContext:self.managedObjectContext];
// [[segue destinationViewController] setSelectedClient:selectedClient];
}
}
You can create segues directly from the startingViewController to multiple destinationViewControllers that can then be "performed" programmatically. You do not need to create any hidden buttons for them, which does seem like a hack.
OK I came up with a solution in keeping with the storyboard that I like.
Example:
My tableview has 2 sections, grouped, and cells are dynamic prototype. Section 0 contains one row/UITableViewCell & I don't want it to segue. Section 1 contains multiple cells that I want to trigger the segue & drill down into the detail.
In Storyboard:
I removed the segue linking the tableviewcell to the destination view controller.
I made a 'generic' segue linking the source view controller directly to the destination view controller.
In the attributes on the segue, I set the identifier ('EditTimePeriod') and set the type to Push (I presume Modal would work just the same).
In the source view controller:
In the prepareForSegue method I handled both the common 'AddTimePeriod' segue I control-dragged from my UIBarButtonItem (Add), along with the 'generic'(vc-->vc) 'EditTimePeriod' segue.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// handle the click of the 'Add' bar button item
if([segue.identifier isEqualToString:#"AddTimePeriod"]) {
TimePeriodViewController* tpvc = (TimePeriodViewController*)segue.destinationViewController;
tpvc.delegate = self;
// database & entity stuff for adding the new one to the mOC, etc
}
// handle the click of one of the 'editable' cells -
if([segue.identifier isEqualToString:#"EditTimePeriod"]) {
TimePeriodViewController* tpvc = (TimePeriodViewController*)segue.destinationViewController;
tpvc.delegate = self;
TimePeriod * newTP = [self.timePeriodArray objectAtIndex:self.tableView.indexPathForSelectedRow.row];
tpvc.timePeriod = newTP;
}
}
Then I implemented the tableView:didSelectRowAtIndexPath method, and put my condition in here. If the selected row was outside of section zero I called the EditTimePeriod segue manually, defining the sender as the selected tableviewcell:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(self.tableView.indexPathForSelectedRow.section!=0){
[self performSegueWithIdentifier:#"EditTimePeriod" sender:[tableView cellForRowAtIndexPath:indexPath]];
}
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
return;
}
would be nice to code the cell in section 0 so that it is not selectable in the first place!
Hope this helps though.
** and then 5 minutes later I took another look and realized I could just move the data from section 0 into the section header, which is more intuitive and wasn't being used anyway. leaving the design open for a standard segue from each tableviewcell without needing any condition/check. Was a good exercise anyway though :)

How to refresh/reload a UITableView

I have a table View and a uibutton.
When i click on uibutton, it will display a model view control using presentModelviewcontroller method.
I have a text field and save button in the presentmodelview.
Please let me know how to reload table view when the user click's on presentmodelview save button
If you need the presentModalViewController to be removed and then the tableView to be reloaded then use this
[yourTableView reloadData];
on the viewWillAppear of the initial view.
First add the item to the array, then reload your table view.
Assuming you declared all properties needed including the array used by the data source.
#property(nonatomic, retain)NSMutableArray *modalArray;
The IBAction on Save button should include the following code:
//Add the item to the array
[self.modalArray addObject:[NSString stringWithFormat:#"%#",txtField.text]];
//Rest of your code, dismiss the modal view
Once dismissed, you need to reload the table view to show up the recent value saved on the modal view.
[self.yourTableView reloadData];
reloadData will call implicitly the data source method tableView:cellForRowAtIndexPath: which will loop the array again and so show you the new value.
In a nutshell,
YourViewControllerClass * vc = [[YourViewControllerClass alloc]init];
[self presentViewController:vc animated:NO completion:nil];
Hope this helps :)
when you want reload tableview please use below line
[self.tableView reloadData];

Resources