I have a UITableView that contain about 20 rows in the iPad's viewport. I have a interval timer that will call UITableView's reloadData regularly(post it to UI thread).
Now when I scroll through the UITableView with medium speed (not so fast), that UITableView will refresh with flickering effect.
I have to write a function to manually update the UITableViewCell label by looping through all the items in the array (this array keep all the items that show on UITableView). I will execute this function when timer is running instead of calling reloadData (as I mentioned above). Then the flickering issue is gone.
I believe that reloadData should be better than looping through all the data because reloadData will only refresh the current showing Cells instead of all the rows, but I couldn't figure out why the flickering happens. Anyone know why?
One thing I have to mention is I did use the CellIdentifier correctly to reuse the cell and only create the cell when the retrieved cell is null.
Moreover, I do not have this issue in iPhone and I believe that it is because iPhone has lesser row compare to iPad.
Anyone can give some explanation about this issue?
I had the same problem with flickering when using reloadData. I solved it by using indexPathsForVisibleRows and cellForRowAtIndexPath: to only update the visible cells. Performance is good since I don't have to iterate over the whole data set, but only a limited number of visible cells.
reloadData causes the tableview to recreate the visible cells on screen which can result in a flickering since the cells get destroyed. There are better ways to reload the tableview. Are you using Core Data? If so the NSFetchedResultsController and it's delegate are a great way to update a tableview since it listens to changes in the underlying datasource and only updates the appropriate cells.
Related
I wanted to know something that I found regarding tableviews. I have UITableView whose items are being generated dynamically, means rows. Now whenever I scroll UITableView to end and stretch the scroll up and release it (u know iPhone style), my cellForRowAtIndexPath gets called. I noticed this because I had my NSLog there. Does this happen normally?
Actually, thing is I am also lazy loading image for UIImageView in each row inside tis method, so I think because of this my lazy loader is also getting called and I don't want this.
This is a normal behaviour. The method cellForRowAtIndexPath is getting called for the new rows which are now visible. This makes the whole table more responsive, because it does not have to render all the rows at same time.
I have a UITableView. each row is heavy object with videos, images etc.
When user scrolls this view how can I release the memory of not visible rows and load the current visible rows?
I assume you're talking about releasing memory that's used by the images and videos of your row, and not the row itself.
In your tableview delegate,
-(void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView
tells you when the tableview scrolling has stopped.
[myTableView indexPathsForVisibleRows]
gives you an array of what is visible.
If your row is not in this array, it is not visible, and you can do your image/video cleanup on it.
Are you recycling UITableViewCells as per Apple's recommendations? If not, you MUST read Apple's docs. Inside the cellForRowAtIndexPath: delegate you should have something [customCell setMediaObjects:]. Inside your customCell class you can release all the previous mediaObjects from memory.
As others have said, you should make sure you are recycling cells properly, and not destroying things you would need to recreate anyway when the cell is reused.
But, you may want to release other assets that the cell or its views are retaining. Or if that cell has any pending download requests, for example, you may want to reset their priority or even cancel them when the cell is offscreen.
I think the cleanest way to do this is to just override -[UITableViewCell prepareForReuse]
This is called when the cell is put back into the reuse queue. If the user is moving up and down the table quickly, you may not want to clean the cell up the moment the cell is off the screen (by looking at indexPathsForVisibleRows, for example).
But when the cell is actually put back in the reuse queue, that is a good time to do that work since you know that cell won't appear again on screen until you dequeue and configure it again.
A Closer Look at Table-View Cells - Apple Documentation
When you call dequeueReusableCellWithIdentifier first 10 (just ten cells can be shown at screen at one moment) cells will be created, then they will be just loaded and configured for showing.
So, cells are not released.
I have a tableview with imageviews and textviews in each cell. When my view is loaded one of the textviews is invisible. But when I start scrolling the textview appears, so that my view looks as it is supposed to look. Does anyone know why this is happening?
P.S. I have read about reusing cells when scrolling so I have been very careful to construct my cells correctly.
Without code, no one can give you a exact answer. But for a guess....
Is your data is getting populated after your table call cellForRowAtIndexPath? When the cell populates the first time, no data, so the cell is in it's unformatted state. By the time you can interact with the table and scroll it off and on screen (which calls cellForRowAtIndexPath again), the data has been populated and so the cell looks as expected.
You can test this by putting a breakpoint in your cellForRowAtIndexPath method and check to see if your data objects are initialized or still set to nil.
Hope to get solution to this problem. I have been stuck on it since a long time now.
I have a a tableView which has custom labels drawn upon the cell using CGRect. I receive the data from a web service in arrays. Initially i display a line of data on the cells. When the user selects a cell, I call reloadsRowAtIndexPath to increase the height of selected row. In the process, cellForRowAtIndexPath gets called again. I keep track of this by a flag, and when cellForRowAtIndexPath gets called again, I display the two more lines of data from arrays, on the cell.
What i am getting is all overlapping data on one other. I tried to remove already placed labels in didSelectRowAtIndexPath, but to no avail.
Please help me on this
Thanks in advance.
In your cellForRowAtIndexPath method, when the selected row height needs to increase, do you create a new UITableViewCell object or change an already allocated one?
Please can you post your cellForRowAtIndexPath method code to help track this down?
I'm curious just how expensive in as far as resources go is UITableView's reloadData? I have an app which will make roughly 10 subsequent HTTP requests, and as it gets data / preps, it reloads the tableView. As the data set grows larger and larger, it's becoming very sluggish. I'm trying to figure out if it's because of the amount of times I'm reloading the tableView or because of how I'm grabbing/parsing the data.
What's the best practice in this case?
From UITableView.h:
- (void)reloadData; // reloads everything from scratch. redisplays visible rows. because we only keep info about visible rows, this is cheap. will adjust offset if table shrinks
"This is cheap."
implement your table view methods well and it'll be no big deal to call this function all the time.
On a side note, you should try to use the appropriate methods to animate adding and removing rows if you are thinking of using reloadData for that.
The best practice is to have your implementation of cellForRowAtIndexPath: do as little work as possible. In fact, it really shouldn't be doing any work except populating the UITableViewCell instance with the data it needs to display.
You should be using cached UITableViewCells so you don't have to allocate a new cell each time. If you can do your parsing and such in a separate thread and make the parsed data, ready to present, accessible to cellForRowAtIndexPath:, you shouldn't have any performance problems.
You didn't say if you were using a custom UITableViewCell subclass, but if you are, deep view hierarchies can also present a performance problem, since each view in the hierarchy gets drawn. The flatter you can make UITableViewCells, the better.
Hope that gets you moving in the right direction.
Best thing to do is profile your app to see where it is slow.
That said, if your table cells are all the same height, then I think
reloadData
only has to call
cellForRowAtIndexPath
for cells that are visible on screen.
Table view reload expense is:
Figuring out how many sections and
rows per sections you have
getting row heights.
Row heights in particular are figured out for all elements of the table, anytime you call reload data.
The remaining expense is cellForRowAtIndexPath, which is usually not too bad because it only is called for as many rows as are on the screen. It can be bad when scrolling if you do not reuse cells like you are supposed to.
The key for you is probably, to ask yourself what triggers the HTML load and possibly move that into a background thread.
Boot To The Head is correct.
I'm doing a progressive one-by-one article list update in Instapaper, and I call -reloadData on each completed download. Sounds similar to what you're doing. It doesn't result in any noticeable performance slowdowns.