This functions perfectly, but I want to make it an once-function, not fixed-function. When I change tableview with other data, the data displays at the index from previous tableview. So my solution to this is implementing the code below. When I implement this, it works, but when I scroll down, it scrolls up all the time, so it is virtually impossible to scroll down further. Any idea how to make it performs only once when I change tableview?
The code:
[tableView scrollRectToVisible:CGRectMake(0,0,1,1) animated:NO];
Edit 21 august:
Guys, thank you very much! The code was in cellforrowatindexpath. I moved it to inside the function which changes tableview and it works like a charm :D
You could override the reloadData method if that is how you are reloading the Table View with new data and put the code in there. Something like this in your table view controller should suffice:
- (void)reloadData {
[super reloadData];
[tableView scrollRectToVisible:CGRectMake(0,0,1,1) animated:NO];
}
If it's scrolling up every time you scroll down, I assume you put the code in the cellForRowAtIndexPath method which will get called every time you want to present the cell. This is not the correct place to put that code.
It IS a once-function. Most probably, this code of yours is executing again & again. If you have kept this in a function such as cellForRowAtIndexPath:, which is called frequently, that may be the cause of this problem. Where have you put it?
HTH,
Akshay
Related
I have 5 view controllers, which are in a navigation controller hierarchy. When I reach my last view controller, there's a button that lets me go back to the "Home" view controller (named CardWalletViewController) which is a table view controller. Here's the method I have in my last VC (PointsResultsVC)
- (IBAction)homePressed:(id)sender {
NSArray *VCs = [self.navigationController viewControllers];
[self.navigationController popToViewController:[VCs objectAtIndex:0] animated:YES];
}
CardWalletVC's cells is being filled up by values coming from the saved instances of a Card in NSUserDefaults and it works fine.
Now, what I want is to update the value in my CardWalletViewController, which is the points of a card coming from my PointsResultsVC. Note that this points is saved in NSUserDefaults.
Upon the process of trying to update of the value shown in my CardWalletVC, I placed [self.tableView reloadData]; inside -viewDidLoad, -viewWillAppear, and -viewDidAppear of the said class. I tried placing it one by one in each of this methods, yet it doesn't seem to work.
Advice Please.
EDIT: problem solved
This one served as my guide Save data from one tab and reloadData in another tab.
And as I have discovered, -viewDidLoad of a certain class will only be called once, all throughout runtime of app. Whereas -viewWillAppear, it will be called every time the view appears.
So, I just moved the way I am loading the values saved in NSUserDefaults from -viewDidLoad to -viewWillAppear. Also, inside -viewWillAppear I placed the [self.tableView reloadData]. Then there, problem solved.
There's a lot of things that could be going wrong so you'll need to provide more info to narrow it down.
First of all, viewDidLoad will not be called so you can remove it from here. Both viewWillAppear and viewDidAppear will be called, so you only need it one of these 2 methods.
Next, you need to determine what the actual issue is.
1 - is self.tableView a proper reference to the table? Are you properly maintaining the reference?
2 - is the table actually reloading but using the old data, or is it not reloading at all? You can log the willDisplayCell method to see what is going on when the view appears.
With that info, the root cause can be narrowed down to a solvable problem.
I have an app that uses a UITablewView and in that TableView there is an NSMutableArray that holds the data to be displayed in the TabelView.
The problem is in my TableView Controller I use:
[[self tableView] reloadData]
To reload the TableView data and it works fine for a couple of times but doesn't work on the 3rd time and instead it changes the array count in a weird way.
Now I read similar question here and most likely I have 2 instances of the TableView or the TableViewController but I can't figure out how to troubleshoot this? How to detect if there are 2 instances of the object and fix that?
EDIT: Here is a pic how my navigation goes
So the 1st round of going from ScrollView to TableView things show up correctly. Then I go to UIView and back to TableView and it's working fine. So I go back all the way to ScrollView and back again to TableView and it's good.
But when I go to the UIView for this time then back to TableView this problem happens. TableView doesn't display the changes. So I put a breakpoint just before [[self tableView] reloadData] and found out that the array _displayedObjetcs gets its count changed. -1 actually. see the following screen shots b4 and after I step over the reloadData
and then
My immediate thought is that your array is not being retained properly, by your application. Your "weird" count is probably a number like 234791..., which is highly indicative of an array that has been released incorrectly. Therefore, I would check how your are retaining and releasing this array.
However, without more posted code, it is impossible to help you further.
Sometimes tiny looking problem is ignored to handle in the last but you never know that will become nightmare for you, happening with me.
Thanks in advance, problem my app's settings page contains tableView and every setting element is one of the view. One of the setting item (row) offers show expands a few list of items in another listTableView. After making a selection in listTableView when i come back to my settings tableView using navigationItem.leftButton (Back), selected item value overlaps the previous item's value, in the sense [tableView reloadData] in viewWillAppear works fine but tableView rows are not fresh drawn. It doesn't refresh the cell's UI.
Note that if settingTableView has any subview like UIButton etc it has the latest value, i can use that as workaround but the only problem is when is select this row again Selection has old value that overlaps new value on selecting the row.
I will appreciate any suggestion or sample code using will be great help.
Thanks a ton
Amit Singh
Use [tableView reloadData]; in your viewWillAppear method.
or use [tableView reloadData]; in viewDidAppear method
The problem you are facing is perhaps due to portion of cell that is reusable and the one that is not reused. Check out the code you are writing inside the block of
if(cell==nil){}
components you have created inside block will not get recreated and others might be recreating causing the overlapping on the cell.
In my case, I had to use [self.tableView reloadData]; rather than [tableView reloadData]; in the viewWillAppear method.
I have a UITableview that I load with data async so the tableview might appear without data.
I have tired the ReloadData method but the tableview remains empty until I scroll the tableview, suddenly the data appears.
The same thing happens when I load a tableview as a detailedview and switching between items, the previoud items data appears first and as soon as I scroll in the table view it shows the correct data.
My guess is that the ReloadData method works just fine, but I need to redraw the tableview somehow, any suggestions on how to solve this?
/Jimmy
You said you're populating content asynchronously but did you invoke the reloadData in the context of the main thread ? (and not via the thread that populates the content)
Objective-C
[yourUITableView performSelectorOnMainThread:#selector(reloadData)
withObject:nil
waitUntilDone:NO];
Swift
dispatch_async(dispatch_get_main_queue(), { self.tableView.reloadData() })
Monotouch
InvokeOnMainThread(() => this.TableView.ReloadData());
Yonels answer is perfect when your view is currently visible to the user (e.g: User presses a reload button which populates your UITableView.)
However, if your data is loaded asynchronously and your UITableView is not visible during the update (e.g: You add Data to your UITableView in another View and the UITableView is displayed later by userinput), simply override the UITableViewController's viewWillAppear method.
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.tableView reloadData];
}
The positive effect is that your UITableView only reloads it's data once when the user actually want's to see it, not when new items are added.
I had the similar issue today(Storyboard in iOS 7.0).
I was using table View inside a UIViewController.When the view was loaded everything was working fine; all the delegates were getting called.However ; When the underlying dataSource(in my case,Array) was modified; the visible table rows were not getting updated.They were updated; only when I was scrolling the table view.
Tried everything; calling reloadData on Main thread;calling reload in ViewWillAppear; nothing worked.
The issue that I found ; was that I had not made the connection in storyboard; for the table view with the reference Outlet.The dataSource and delegate were set though.
I did not think that it could be the issue; as everything was working fine at the first go.
Hope it helps someone.I had some terrible time to find this out.
I guess it wasn't reloaded.
When you scroll the cells to out of screen, then…
tableView: cellForRowAtIndexPath:
…will be called. So it will be reloaded.
I guess UITableView variable is not validated.
If you use UITableView as a main view, you can try this.
[self.view reloadData];
or
[self.tableView reloadData];
Swift 4:
DispatchQueue.main.async { self.tableView.reloadData() }
After somewhat naively copying in yonel's solution and calling it good I realized that calling performSelectorOnMainThread:withObject:waitUntilDone: fixed the symptom, but not the problem. The bigger problem is that you are making UI updates while still in the context of the asynchronous or background thread.
This is what my code looked like:
dispatch_queue_t queue = dispatch_queue_create("com.kyleclegg.myqueue", NULL);
dispatch_async(queue, ^{
// Make API call
// Retrieve data, parse JSON, update local properties
// Make a call to reload table data
});
When it should look like this:
dispatch_queue_t queue = dispatch_queue_create("com.kyleclegg.myqueue", NULL);
dispatch_async(queue, ^{
// Make API call
// Retrieve data, parse JSON, update local properties
dispatch_async(dispatch_get_main_queue(), ^{
// Now make the call to reload data and make any other UI updates
[self.tableView reloadData]
});
});
If the only thing you need to do is call [self.tableView reloadData] it's probably fine to use performSelectorOnMainThread:withObject:waitUntilDone: since it accomplishes the same goal, but you should also recognize what's happening in the big picture. Also if you are doing more UI work than just reloading the table then all of that code should go on the main queue as well.
Reference: A concise example of using GCD and managing the background vs. main thread.
I am trying to do something interesting.
I am pulling some JSON data and populating cells in a UITableView. How can I make the UITableView scroll ever second or so? I want to give the effect that as new data is coming in, the table is scrolling, so it is streaming.
Any ideas?
Yes, use scrollToRowAtIndexPath:atScrollPosition:animated:.
You could also use UIScrollView's scrollRectToVisible:animated: if you want to have more finegrained control and can calculate exactly what your scroll position should be in pixels. (UITableView is subclass of UIScrollView.)
But if you are just adding cells, sounds like you could also just use insertRowsAtIndexPaths:withRowAnimation:, this is also "interesting."
Just do this
[table reloadData];
NSIndexPath *myIP = [NSIndexPath indexPathForRow:[arrayIn count]-1 inSection:0] ;
[table scrollToRowAtIndexPath:myIP atScrollPosition:NULL animated:YES];
in anywhere where arrayIn is your array by which your table populate.
you can use uitableviews scrollToRowAtIndexPath to do this....heres a link reference
You can call this method whenever as youd like to scroll your tableview
And you can call performSelector:withObject:afterDelay: for the timer effect - although if you are really pulling in data every second, it's best to just reloadData as you go.