25

I added an infinite scrolling feature and realized that whenever I reload the uitableview, the view flickers..I am not sure how to fix the flickering at this point. Please help, thanks!

I did see a very similar question, but no solution to it. I tried the one the author posted, but it doesn't not work: "remove the tableview from parent view, reload data, put table view back into parent view" (UITableView reloadData - how to stop flicker)

Code:

[self.tableView reloadData];
Gautam Shrivastav
  • 1,198
  • 1
  • 9
  • 22
trillions
  • 3,669
  • 10
  • 40
  • 59

9 Answers9

27

Below code worked for me like a charm!

Objective-C

[UIView performWithoutAnimation:^{
   [self.tableview reloadData];
   [self.tableview beginUpdates];
   [self.tableview endUpdates];
}];

Swift 4

UIView.performWithoutAnimation {
    self.tableView.reloadData()
    self.tableView.beginUpdates()
    self.tableView.endUpdates()
}
DoesData
  • 6,594
  • 3
  • 39
  • 62
Shaunak
  • 707
  • 1
  • 9
  • 29
  • can someone help me with with code in Swift 4 please and why does tableview reloaddata with animation make the table view flicker? – Nishad Arora Mar 26 '18 at 06:02
  • 3
    after so many years, people are still dealing with flickering...this simply means Apple should fix it instead of all of us struggling with it...tricks work..but the code doesn't make any sense when reading it...beginUpdate and then endUpdate and nothing in between. Ahhh....apple please fix it instead :) – trillions May 30 '19 at 03:12
  • @trillions isn't there any lib like DiffUtil in android where I can expect the data to be compared and updated only if it has changed and that too with proper animation? – NIKHIL MAURYA Dec 26 '19 at 06:34
  • Wow! This still works in a 2022. What a surprise – Kostarev Kirill Apr 22 '22 at 12:15
16

As you have guessed, flickering is caused by calling [self.tableView reloadData]; rapidly and repeatedly, especially on iOS 5.x devices. But you probably do not want to reload the entire table, you want to update just the view within the visible cells of the table.

Let's say you want to update each cell of a table to reflect the latest download % as a file is downloading. A method [downloading:totalRead:totalExpected:] gets called in my example, extremely rapidly as bytes are downloading.

This is what NOT to do... reload the table on every little update (in this example, the developer may rely on "cellForRowAtIndexPath" or "willDisplayCell" methods perform the updating of all the visible cells):

    - (void)downloading:(PPFile *)file totalRead:(long long)read totalExpected:(long long)expected {
        // Bad! Causes flickering when rapidly executed:
        [self.tableView reloadData];
    }

The following is a better solution. When a cell's view needs to be updated, find that cell by grabbing only the visible cells from the table, and then update that cell's view directly without reloading the table:

    - (void)downloading:(PPFile *)file totalRead:(long long)read totalExpected:(long long)expected {
        NSArray *cells = [self.tableView visibleCells];

        for(MYCellView *cell in cells) {
            if(cell.fileReference == file) {
                // Update your cell's view here.
            }
        }
    }

EDIT: The docs recommend the same:

Calling this method causes the table view to ask its data source for new cells for the specified sections. The table view animates the insertion of new cells in as it animates the old cells out. Call this method if you want to alert the user that the values of the designated sections are changing. If, however, you just want to change values in cells of the specified sections without alerting the user, you can get those cells and directly set their new values.

mfaani
  • 33,269
  • 19
  • 164
  • 293
Moss
  • 234
  • 2
  • 8
3
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:index] withRowAnimation:UITableViewRowAnimationNone];

whenever you remove or add a table row in updates..the table view reloads and ask the datasource for the number of rows based on which cell is animated to position.

you are removing row from table but not from datasource..so rows are deleted but your datasource still points out that no row is deleted..20 objects are still there. your data source will be something like

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return MyDataModel.count; // 
}

so you need to remove or add new data in datasource also..something like this

   NSIndexPath *index = [NSIndexPath indexPathForRow:i inSection:0];
   [MyDataModel removeObjectAtIndex:index.row];
   [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:index] withRowAnimation:UITableViewRowAnimationNone];
Shubhank
  • 21,721
  • 8
  • 65
  • 83
  • thanks! but actually maybe i should NOT remove the cells...i am just trying to fix the flickering so i thought removing cells and reloading them again will help..hmm...if i really remove all the objects from MyDataModel, how and when should i load it back? – trillions Mar 04 '13 at 08:10
  • can you post a video to explain flickering..i haven't came across that yet – Shubhank Mar 04 '13 at 08:29
  • please forgive me, i dont know how to capture a video. What kind of tool should i use? flickering is like blinking.. – trillions Mar 04 '13 at 08:32
  • ah, thanks @ShashankKulshrestha ! I just realized that i can't do this, since it's confidential ...yes, bad..But now I suspect the flickering is caused by some animation on the first 10 rows. then reload data may call into the animation. but i am not sure. will check in the morning and update this thread. – trillions Mar 04 '13 at 09:01
  • @Barfi so when you update the scrolling table by appending more data to the data model, you've never seen any screen flickering/blinking, right? please help me confirm. This will ease my investigation, so i can investigate the animation on that page. In reality, i dont think animation needed there....it could be the culprit. – trillions Mar 04 '13 at 09:02
  • i haven't seen any flickering before. when updating or reloading table – Shubhank Mar 04 '13 at 09:42
3

Why don't you simply call reloadSections method instead of [self.tableView reloadData];

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
Zoeb S
  • 695
  • 1
  • 7
  • 21
2

Just in case all other answers do not solve your problem, I post my solution.

If you use estimated height estimatedSectionHeaderHeight or estimatedRowHeight or -(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath, and with dynamic row count for each section (e.g. expandable two level tableView)

you should stop using this and implement -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath to return the correct height.

ooops
  • 761
  • 8
  • 18
2

Try this:

UIView.performWithoutAnimation {
    self.tableView.reloadRows(at: [indexPath], with: .none)
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
Abhi
  • 267
  • 2
  • 4
1

Refer your cellForRowAtIndexPath delegate method. You might be doing some operation that might cause a flick. In my case, I was setting an image of a image view with animation. So whenever I reload the table, it was flickering due to that animation.

I removed it and worked for me..

NSPratik
  • 4,714
  • 7
  • 51
  • 81
1

what work in my project was :

UIView.PerformWithoutAnimation(() =>
{
tableView.ReloadData();
tableView.LayoutIfNeeded();
});

(it's in c# xamarin...but the same with swift of objective c)

gal danay
  • 11
  • 1
0

y you are using deleteRowsAtIndex? If you reload table all table delegate methods are called. I think it is taking time to delete all rows and then again reload. Just use reload method and try.

Durgaprasad
  • 1,910
  • 2
  • 25
  • 44
  • Let me remove the delete rows stuff in my code as well as in here. It gets us distracted...I used reload data method, but it flickers, the screen flickers so it will not be acceptable by the product...and I dont know how to fix it. – trillions Mar 04 '13 at 08:12