Reload UITableView from another tab - iphone

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.

Related

Get download progress from different ViewController

I have a VideoListController. It has list of videos with download button. When I press the download button, the control is transferred to DetailViewController. In DetailViewController, I am using AFNetworking to download file.
If I go back to VideoListController from DetailViewController. How can I know progress of download or when download gets completed from VideoListController. I want to know this because based upon that I will reload the list to show play button instead of download.
I think that the best solution for your problem would be to create a custom delegate protocol that the DetailViewController and the VideoListController can use to communicate with each other. Check this post for additional information How to use custom delegates in Objective-C
In a nutshell the strategy is the following:
1. The DetailViewController defines a delegate protocol that it uses to pass events to its delegate
2. The VideoListController becomes the delegate to that it knows whenever an upload has progressed or been completed
3. The VideoListController keeps track of which DetailViewControllers have completed the download
Here is come code:
DetailViewController.h:
#class DetailViewController;
#protocol Delegate <NSObject>
- (void) detailViewController: (DetailViewController *) theDetailViewController didFinishDownloadingVideoWithResults:(BOOL)successful;
#end
#property (nonatomic, weak) id<DetailViewController> delegate;
DetailViewController.m:
Whenever a download is complete do the following:
if ([[self delegate] respondsToSelector:#selector(detailViewController:didFinishDownloadingVideoWithResults:)]){
[[self delegate] detailViewController:self didFinishDownloadingVideoWithResults:YES];
}
Now, in the VideoListController.m make sure you establish yourself as the delegate of the DetailViewController.
[theDetailViewController setDelegate:self];
And implement the delegate method. You can for instance have a dictionary that defines which DetailViewControllers have completed the download:
- (void) detailViewController: (DetailViewController *) theDetailViewController didFinishDownloadingVideoWithResults:(BOOL)successful{
detailViewControllersDownloadInformation[theDetailViewController] = #(successful);
}
Now, whenever you need to check if a DetailViewController did indeed complete a download, all you have to do is check that dictionary
if (detailViewControllersDownloadInformation[theDetailViewController] && detailViewControllersDownloadInformation[theDetailViewController] == #(YES)){
// Did download a video
}
Keep in mind that the solution I provide will only let you know if the download has been completed. If you also want to keep track of the progress you need to pass that as an additional parameter in the delegate. We are also assuming that you keep all of the DetailViewControllers in memory. If you release and reuse them you will need to keep track of which element was downloaded in a different data structure.
I got it working using NSNotificationCenter.
In viewDidLoad of DetailViewController, I added this
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieDownloadDidFinish)
name:#"MovieDownloadDidFinishNotification"
object:nil];
When download gets complete. I call this:
[[NSNotificationCenter defaultCenter] postNotificationName:#"MovieDownloadDidFinishNotification" object:self];
I remove the observer from DetailViewController when when backbutton in navigation controller is clicked
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"MovieDownloadDidFinishNotification" object:nil];
And added method in DetailViewController that is called when download gets completed.
-(void) movieDownloadDidFinish {
NSLog(#"MovieDownloadDidFinish on DetailViewController");
}
Now in viewDidAppear of VideoListController, I added the observer
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieDownloadDidFinish)
name:#"MovieDownloadDidFinishNotification"
object:nil];
And in viewDidDisappear Of VideoListController, I remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"MovieDownloadDidFinishNotification" object:nil];
And added method in VideoListController that is called when download gets completed.
-(void) movieDownloadDidFinish {
NSLog(#"MovieDownloadDidFinish On VideoListController");
}
In this way, when DetailViewController is visible, the method movieDownloadDidFinish of DetailViewController is called and similarly movieDownloadDidFinish of VideoListController is called when VideoListController is visible.

how to call function from another class and reload that view from the current class?

I am working on an application which uses bump technology.I do have four tab in which one is a table view .I wrote this bump API in app delegate class so that when the application is open it should be able to transfer the data.Transfer function is working properly.But the problem is that I am inserting the data into sq-lite and the data from sqlite is displayed in one of the tab bar item view.So when the user selects this tab bar item and receives the data i would like to insert and also reload the view with the new changes.As told before insertion i working.But the problem is reloading the view.Can any one help me with this problem?
You can perform insertion in background using NSOperation and post notification whenever you insert/edit a record. Add listener to the View controller where you are displaying data.
So whenever the controller receive the notification, it will call the method to reload data from database.
#implementation MyClass
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id) init
{
self = [super init];
if (!self) return nil;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reloadData:) name:#"COREDATA_OBJECT_EDITED" object:nil];
return self;
}
- (void) reloadData:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"COREDATA_OBJECT_EDITED"])
{
//load records from database and reload tableview
}
}
#end
//Method where you are saving data objects in some other class
- (void) saveDataObject
{
//Save Data object, if saved successfully then post notification to listener to reload the data
// All instances of MyClass will be notified
[[NSNotificationCenter defaultCenter] postNotificationName:#"COREDATA_OBJECT_EDITED" object:self];
}

Can I watch an NSNotification from another class?

I'm trying to get my head around NSNotificationCenter. If I have something like this in my App Delegate:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(something:)
name:#"something"
object:nil];
-----
-(void)something:(NSNotification *) notification
{
// do something
}
Can I somehow watch this in another view controller? In my case, I'd like to watch it in a view controller with a table, and then reload the table when a notification is received. Is this possible?
Yes you can do it like this:
In class A : post the notification
[[NSNotificationCenter defaultCenter] postNotficationName:#"DataUpdated "object:self];
In class B : register first for the notification, and write a method to handle it.
You give the corresponding selector to the method.
//view did load
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleUpdatedData:) name:#"DataUpdated" object:nil];
-(void)handleUpdatedData:(NSNotification *)notification {
NSLog(#"recieved");
}
Yes you can that is the whole purpose of NSNotification, you just have to add the View Controller you want as an observer exactly the same way you did on your App Delegate, and it will receive the notification.
You can find more information here: Notification Programming
Of course it's possible, that's the whole point of notifications. Using addObserver:selector:name:object: is how you register to receive notifications (you should do this in your table view controller), and you can use postNotificationName:object:userInfo: to post a notification from any class.
Read Notofication Programming Topics for more info.
You can register to observe notifications in as many classes as you like. You simply need to "rinse and repeat". Include the code to register as an observer in your view controller (perhaps in viewWillAppear:) and then reload the tableView from your method:
- (void)viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(something:) name:#"something" object:nil];
}
-(void)something:(NSNotification *) notification
{
[self.tableView reloadData];
}
It's also a good idea to de-register the view controller once you no longer need the notifications:
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
You should just add that as an Observer and give a different selector method if you want that viewController to behave differently when that notification is posted.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(somethingOtherThing:)
name:#"something"
object:nil];
-(void)somethingOtherThing:(NSNotification *) notification
{
// do something
}

TableView not reloading from NSNotification

I'm having some trouble getting a tableView to reload using NSNotification.
My set up is that I have a filter view which allows the user to apply filters to the table view, once they click to change a filter I am sending an NSNotification which is picked up in the AppDelegate, this then reloads the core data applying the filters as a predicate.
Once the data has been loaded from core data I post another Notification to the tableView which tells it to reload it's data.
Using NSLog's I can see that the notifications are being sent and received although the [self.tableView reloadData] is doing nothing.
Here is my function to reload the data:
-(void)reloadTable:(NSNotification *)notification {
NSLog(#"reloading table");
[self.rootTableView reloadData];
}
Calling reload in the same way from inside the controller while it is currently in view works fine, so I'm pretty stuck as to why this isn't working.
Is the notification arriving on a thread other than the main thread? It would be if the notification were sent from a background thread. If this is the case, you'll need to marshall the reloadData call to the main thread. Something like this:
[tableView performSelectorOnMainThread: #"reloadData" withObject:nil waitUntilDone:NO];
This is for catching notification. You can put this in viewDidLoad.
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center addObserverForName:kSFAccountsChanged object:nil
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[tblView ReloadData];
}];
}
The code below will fire a notification:
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center postNotificationName:kSFAccountsChanged object:self];
1)
Have you attached your table to rootTableView in interface builder?
Try adding
NSLog(#"%#", self.rootTableView);
This should not be null :)
2)
If you have attached correctly, can you post the code in your table view delegate methods to see what's going on in there?

How to refresh UITableView after app comes becomes active again?

I would like my UITableView to reloadData once my app is active again, after a user exits the application. I know I need to implement (in my app delegate):
- (void)applicationDidBecomeActive:(UIApplication *)application
but im not sure how to reference the current UITableView?
UPDATE:
My UITableView is a separate controller. It is actually presented as follows
AppDelegate > Root View Controller > Pushes UITabBarController modally which has a UITableViewController
following up on Ole's answer above
add this when initializing the viewcontroller
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(becomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
add the actual method in the controller
- (void)becomeActive:(NSNotification *)notification {
NSLog(#"becoming active");
}
be sure to clean up the notification
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
If you can't access your view controller from the app delegate, you could also have your controller listen to the UIApplicationDidBecomeActiveNotification notification.
you can create your class called TableViewManager. in there register list of UITableView so that you can refresh any table you want.
it's like this, in yourTableViewManager class, you have a method called
- (void)RefreshTableView:(UITableView *)tableView {
if(tableView != nil)
[tableView reloadData]; }