Tableview Reloaddata VS. Beginupdates & Endupdates

iOS using UITableView reloadData vs endUpdates

  1. It depends. If you want just refresh data without any animation then use reloadData. In the case when you build up an user-friendly smooth data changing animations, it would be better to calculate the diff and insert/delete rows with some beautiful animation

  2. User is not interacting with tableView infinitely. You may track when table is not dragging and update the data, but refreshing view to show actual data is common practice today. For example, at the web it is AJAX technology. Also, as I mentioned in 1, use animation to attract user's attention to new data

  3. As it mentioned in the comments, in your case using NSFetchedResultsController would be better

UITableView beginUpdates() and endUpdates() clarification

I think I've found the clarification I was looking for. From https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/TableView_iPhone/ManageInsertDeleteRow/ManageInsertDeleteRow.html, under the heading "Batch Insertion, Deletion, and Reloading of Rows and Sections" and subheading "Ordering of Operations and Index Paths"

You might have noticed something in the code shown in Listing 7-8 that seems peculiar. The code calls the deleteRowsAtIndexPaths:withRowAnimation: method after it calls insertRowsAtIndexPaths:withRowAnimation:. However, this is not the order in which UITableView completes the operations. It defers any insertions of rows or sections until after it has handled the deletions of rows or sections. The table view behaves the same way with reloading methods called inside an update block—the reload takes place with respect to the indexes of rows and sections before the animation block is executed. This behavior happens regardless of the ordering of the insertion, deletion, and reloading method calls.

Deletion and reloading operations within an animation block specify which rows and sections in the original table should be removed or reloaded; insertions specify which rows and sections should be added to the resulting table. The index paths used to identify sections and rows follow this model. Inserting or removing an item in a mutable array, on the other hand, may affect the array index used for the successive insertion or removal operation; for example, if you insert an item at a certain index, the indexes of all subsequent items in the array are incremented.

While that's barely parsable, I think it means the second of example in the question is correct.

UITableView jumps up after begin/endUpdates when using UITableViewAutomaticDimension

Actually I found a nice method to fix this.. It drove me crazy but look:

So you

  • Have a table with expandable content
  • Wanna animate a cell's constraints (height for example)
  • And therefore you call tableView.beginUpdates() and tableView.endUpdates()

And soo the table jumps..

As others have said before, it is because updating the tableView makes the tableView Scroll

The solution?

Let's assume your code looks like this:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell.heightConstraint = 100
UIView.animate(withDuration: 0.15, animations: {

self.view.layoutIfNeeded()
self.tableView.beginUpdates()
self.tableView.endUpdates()
}, completion: nil)
}

Then to fix the jumping issue you have to save the current tableView scroll position until the tableView.endUpdates() being called.

Like this:

var currentScrollPos : CGFloat?

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Force the tableView to stay at scroll position until animation completes
if (currentScrollPos != nil){
tableView.setContentOffset(CGPoint(x: 0, y: currentScrollPos!), animated: false)
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell.heightConstraint = 100
UIView.animate(withDuration: 0.15, animations: {

self.currentScrollPos = self.tableView.contentOffset.y

self.view.layoutIfNeeded()
self.tableView.beginUpdates()
self.tableView.endUpdates()

self.currentScrollPos = nil
}, completion: nil)
}

What's the difference between tableView.reloadData and tableView.reloadRows?

Check out the apple documentation for this -

1. reloadData() :

Reloads the rows and sections of the table view.

Description : Call this method to reload all the data that is used to construct the table, including cells, section headers and footers, index arrays, and so on. For efficiency, the table view redisplays only those rows that are visible. It adjusts offsets if the table shrinks as a result of the reload. The table view’s delegate or data source calls this method when it wants the table view to completely reload its data. It should not be called in the methods that insert or delete rows, especially within an animation block implemented with calls to beginUpdates() and endUpdates().

2. reloadRows(at:with:) :

Reloads the specified rows using an animation effect.

Description:

Reloading a row causes the table view to ask its data source for a new cell for that row. The table animates that new cell in as it animates the old row out. Call this method if you want to alert the user that the value of a cell is changing. If, however, notifying the user is not important—that is, you just want to change the value that a cell is displaying—you can get the cell for a particular row and set its new value.

When this method is called in an animation block defined by the beginUpdates() and endUpdates() methods, it behaves similarly to deleteRows(at:with:). The indexes that UITableView passes to the method are specified in the state of the table view prior to any updates. This happens regardless of ordering of the insertion, deletion, and reloading method calls within the animation block.

https://developer.apple.com/documentation/uikit/uitableview/1614862-reloaddata
https://developer.apple.com/documentation/uikit/uitableview/1614935-reloadrows



Related Topics



Leave a reply



Submit