iPhone - Refreshing TableView VC from higher ViewController - iphone

I have ViewController (A) with TableView where each row is a directory name. Each row is pushing a new ViewController (B). Inside ViewController B I am running method to delete the currently opened directory. However, when I pop the view and go back to TableView I obviously still have this directory on list. How can I fix it?
How can I refresh the TableView while going back in navigation?
And no, simple [self.tableView reloadData] inside -viewWillAppear doesn't really work.
Code:
My -viewWillAppear:
- (void)viewWillAppear:(BOOL)animated {
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
self.arrFolders = [[NSMutableArray alloc] init];
[self allFilesInDocuments:docDir];
}
-allFilesInDocuments is just adding items to array ([arrFolders addObject:folder];).
Inside -tableView:cellForRowAtIndexPath: I add data with
cell.textLabel.text = [arrFolders objectAtIndex:indexPath.row];

Use a NSNotification.
In the viewDidLoad of ViewController (A) register for a notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deletedRow:) name:#"deletedRow" object:nil];
Also add the selector function:
-(void) deleteRow:(NSNotification *)notif{
[self.tableView reloadData];
}
Finally in the child view controllers, in your Delete function post the notification:
[[NSNotificationCenter defautCenter] postNotificationName:#"deletedRow" object:nil userInfo:nil];
Hope it helps

An edit to the datasource and a reload in -viewWillAppear should of worked though failing this you could perform the update via an parent view controller call or an NSNotification.

Related

Call [tableView reloadData]; on a viewController from a modalViewController

I have a modalViewController that comes up over the top of a viewController with a tableView. When the user clicks a button on the modalViewController I want to reload the tableView within the viewController with this:
[tableView1 reloadData];
I do not want to put the reload in the viewDidAppear or viewWillAppear methods as they get called when i do not need the tableView to reload (i.e. when the user clicks the back button to return to the tableView).
Is there a way to do this?
Try
1) write one method which reloads the table data.
2) Call it on the back button clicked.
This is the classic delegate pattern problem, in your modal view controller you need a delegate reference to the current view controller presenting it
//Modal
#protocol ModalVCDelegate
- (void)tappedBackButton;
#end
#class ModalVC: UIViewController
#property id<ModalVCDelegate> delegate;
#end
#implementation
- (void)backButtonTapped:(id)sender
{
if (self.delegate)
[self.delegate tappedBackButton];
}
#end
Now, in your presenting VC, just process this delegate message
//Parent VC
- (void)showModal
{
ModalVC *vc = [ModalVC new];
vc.delegate = self;
//push
}
- (void)tappedBackButton
{
[self.tableView reloadData];
//close modal
}
You can use delegate . If find it more harder then alternative is to use NSNotificationCenter. You can see accepted answer for Refreshing TableView. This is really very short, easy and understandable way.
using Notification like bellow Method:-
Create NSNotificationCenter at yourViewController's ViewdidLoad Mehod
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ReloadDataFunction:)
name:#"refresh"
object:nil];
[super viewDidLoad];
}
-(void)ReloadDataFunction:(NSNotification *)notification {
[yourTableView reloadData];
}
Now you can Call this Notification from your modelViewController BackButton or else you want from calling this Refresh notification like putting this line of code:-
[[NSNotificationCenter defaultCenter] postNotificationName:#"refresh" object:self];
NOTE: postNotificationName:#"refresh" this is a key of particular Notification
Try to use this one
Make a Button and click on this button and than you can reload your data.
This button make custom and use it on background.
- (IBAction)reloadData:(id)sender
{
[tblView reloadData];
}
You can use NSNotification to refresh table on ViewController.
Inside viewController :
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Write code in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadMainTable:)
name:#"ReloadTable"
object:nil];
- (void) reloadMainTable:(NSNotification *) notification
{
[tableView reload];
}
Inside ModelViewController:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ReloadTable"
object:nil];
Here you can also send custom object instead of nil parameter. But be care full about removal of NSNotification observer.

Open View from didReceiveRemoteNotification

I have this question asked few times and I have tried a few different methods but have not been successful.
The latest method I have tried is as followed :
I included the ViewController that I wanted to show. I then put this code in the didReceiveRemoteNotification method.
CarFinderViewController *pvc = [[CarFinderViewController alloc] init];
// [self.window.rootViewController presentViewController:pvc animated:YES completion:nil];
[(UINavigationController *)self.window.rootViewController pushViewController:pvc animated:NO];
This did not work. I think the problem I may be having is that my initial view is not a navigation controller like a lot of the examples show.
This is a picture of my story board> The VC that I want to send the user to is the car finder (bottom right)
Can someone explain to me what I might be doing wrong?
You could use basically postNotification when you receive the Remote Notification
for exmaple in your didReceiveRemoteNotification post notification like this
[[NSNotificationCenter defaultCenter] postNotificationName:#"pushNotification" object:nil userInfo:userInfo];
now in your FirstViewController's you can register the FirstViewController for this notification like this
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pushNotificationReceived) name:#"pushNotification" object:nil];
and in your method
-(void)pushNotificationReceived{
CarFinderViewController *pvc = [[CarFinderViewController alloc] init];
[self presentViewController:pvc animated:YES completion:nil];
}
don't forget to remove the observer from notification in your dealloc method
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
I think the simplest solution would be to show the CarFinderViewController as a modal view instead of trying to push it to a navigation controller which may or may not be visible at the time.
Another important point to avoid further inconsistencies I'd recommend you instantiate your CarFinderViewController from the storyboard instead of directly through the class methods.
Something like:
UIViewController * vc = self.window.rootViewController;
// You need to set the identifier from the Interface
// Builder for the following line to work
CarFinderViewController *pvc = [vc.storyboard instantiateViewControllerWithIdentifier:#"CarFinderViewController"];
[vc presentViewController:pvc animated:YES completion:nil];

Trying to reload a UItableview whenever my plist is updated?

I have a plist that is populated by the user within my app. I am trying to display the contents of that plist in a UITableView and it wont display until after the app is relaunched which means its not updating. Here is what I have:
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
NSString *path = [[NSBundle mainBundle] pathForResource:#"foodList" ofType:#"plist"];
arrayFood = [[NSMutableArray alloc]initWithContentsOfFile:path];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView reloadData];
NSString *path = [[NSBundle mainBundle] pathForResource:#"foodList" ofType:#"plist"];
arrayFood = [[NSMutableArray alloc]initWithContentsOfFile:path];
}
Thanks in advance!
From what i see, you should be calling
[self.tableView reloadData]
after you load the data from plist to foodArray in viewDidAppear...
Whenever you update the pList file simply call the self.tableView reloadData. Also, make sure that the data source you are using for your UITableView is updated. This datasource can be an NSDictionary, NSArray, NSMutableArray etc. The reloadData method of the tableView will trigger the cellforRowIndexPath method where you will create the UITableViewCell.
The best way to update the UITableView with newest data is to overwrite the setter method of data array.
For example your data array is arrayFood so you may have its property as strong or say retain
#property(nonanatomic,stron) NSMutableArray *arrayFood;
then you should overwrite its setter method.
-(NSMutableArray *)setArrayFood:(NSMutableArray *)array
{
//set your data array here and simply call reloadData
[self.tableView reloadData];
}
in that way your tableView always get update whenever your data array changed.
Also use NSNotifications for plist change and update your arrayFood there.
Using NSNotificationCenter may help you here.
In the ViewController that updates your plist, place this code when this update happens:
[[NSNotificationCenter defaultCenter] postNotificationName:#"plistDidUpdate" object:self];
In the ViewController you'll want to add this code to viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(plistDidUpdate:) name:#"plistDidUpdate" object:nil];
Also, add this function in the same ViewController:
-(void)plistDidUpdate:(id)sender{
[self.tableView reloadData];
}

Reload UITableView from another tab

I am having trouble trying to reload UITableView cell data which are being loaded from an XML source.
Here is the scenario. App contains tabs, in one of them there is a tableview which gets it's data from an XML file and works just ok, but the thing is when I want to change the feed category and change the XML from another tab I can refresh the current tableview.
For switching between tabs I use
self.tabBarController.selectedIndex = 1;
and pass the category feed to the other tab which I want to load
xmlParser = [[XMLParser alloc] loadXMLByURL:categories];
and it still loads the same old feed, not the new one which has been passed. I checked with NSLog and the feed value passes properly but it just wont load after switching.
I also tried to [self.tableView reloadData]; from both current tab and the category tab and it didn't work either.
You can use NSNotifications to send a notification from your other tab and have a oberver in your tableview that responds to that notification.
Example
(Tab calling the reload of the tableview) put this code whenever you want to reload the data, so when a button is pushed or a download is finished etc.
NSNotification * notification = [NSNotification notificationWithName:#"updateTable" object:nil];
[[NSNotificationCenter defaultCenter] postNotification:notification];
In the UITableViewController / the class with the UITableView, do the following.
in your viewDidLoad add:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateTableView) name:#"backtolist" object:nil];
Then add the function updateTableView
- (void) updateTableView: (NSNotification*) note
{
//Do whatever needs to be done to load new data before reloading the tableview
[_tableView reloadData];
}
Hope this helps
Ophychius was correct in his suggestion to use Notifications. I'm assuming you have all of the data sources for your table view updating when the XML is finished loading. This also assumes you're using dynamic cells. In the class that loads the XML, post a Notification when the new XML is finished loading.
[[NSNotificationCenter defaultCenter] postNotificationName:#"XMLLoaded" object:nil];
In the table view class, register as an observer for the Notification you posted from the XML class.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reloadTable:) name:#"XMLLoaded" object:nil];
As you can see, this calls a selector when this notification is received. Either call your method where you build the table, or create another simple method to call reloadData from.
-(void)reloadTable:(NSNotification *)notif
{
NSLog(#"In ReloadTable method. Recieved notification: %#", notif);
[self.tableView reloadData];
}
Finally (as Leonardo pointed out below), in your viewDidUnload (or dealloc for ios6) method, remove the class as an observer of that notification.
- (void)viewDidUnload
{
[super viewDidUnload];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
I am just guessing, without having seen the rest of the code.
I suppose your table view has an NSArray datasource, did you make sure that your array datasource is updated too ? Does your xml parser, or controller, transfer those data to the NSArray ?
Because if you call reloadData it is just going to refetch the same array. And if it is not updated, you would get old data.

How to push a View in a NavigationController which is containing in another tab in a TabBarController?

I have a TabBarController with 2 tabs, in one is a MapView and in the other one a simple TableView in a NavigationController. Both display Data from the same source. If any Data in the table is tapped, I add a DetailViewController to the NavigationController and show more details. Now on the MapView I also want to open this DetailViewController when the Data is tapped in the map. What's the best way to do this? I tried some with Notification but this doesn't work well because the TableViewController is finished loading (and registered as an observer) after the Notification is sent.
Here's my code:
MapViewController:
- (IBAction)goToNearestEvent:(id)sender {
if (currentNearestEvent) {
[[self tabBarController] setSelectedIndex:1];
NSDictionary *noteInfo = [[NSDictionary alloc] initWithObjectsAndKeys:currentNearestEvent, #"event", nil];
NSNotification *note = [NSNotification notificationWithName:#"loadDetailViewForEvent" object:self userInfo:noteInfo];
[[NSNotificationCenter defaultCenter] postNotification:note];
[noteInfo release];
}
}
TableViewController:
- (void)viewDidLoad {
[super viewDidLoad];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(loadDetailViewForEvent:)
name:#"loadDetailViewForEvent"
object:nil];
}
- (void)loadDetailViewForEvent:(NSNotification *)note {
Event *e = [[note userInfo] objectForKey:#"event"];
[self loadEventDetailViewWithEvent:e];
}
So I'm very new to iOS / Cocoa programming. Maybe my approach is the wrong choice. So I hope anybody could tell me how to solve such things the right way.
I forgot to declare my structure clearly:
- UITabBarController
- MapView (1)
- NavigationControllerContainer
- NavigationControllerView (2)
- TableView
I want to push a new View from the MapView (1) to the NavigationControllerView (2).
If you're going to use notifications, the fix is to force the second tab to be "created" before it's displayed.
Something like:
UIViewController *otherController = [[[self tabBarController] viewControllers] objectAtIndex:1];
otherController.view; // this is magic;
// it causes Apple to load the view,
// run viewDidLoad etc,
// for the other controller
[[self tabBarController] setSelectedIndex:1];
I don't have access to my code, but I did something similar to:
[[self.tabBarController.viewControllers objectAtIndex:1] pushViewController:detailView animated:YES];
Give this a try and let me know.
I think the observer/notification pattern is the right one. However, you normally want "controllers" to observe "model" objects.
I would create a Model object that contains the selected Event.
When each viewController is loaded, it looks at the "Model" object and directs itself to the selected event.
When any of the viewControllers changes the selected event, it does so in the Model, and then the notification propagates to the other(s) controllers.