TableView append jump

Hey guys,

I rarely use tableView as mostly use CollectionView however have come across a glitch effect when appending onto the tableView then calling reloadData().

Ultimately I'm appending a new message / string into an array, then reloading the UITableView to display the newly appended message. I am scrolling to the bottom of the table using a scroll function:

func scrollToEnd() {
        if numberOfRows(inSection: 0) > 0 {
            let index = NSIndexPath(row: self.numberOfRows(inSection: 0) - 1, section: 0) as IndexPath
            self.scrollToRow(at: index, at: .bottom, animated: true)
        }
    }

What happens is rather than the newly appended message just 'inserting' itself at the bottom of the table with a smooth animation, the whole table is reloaded from the top down and scrolls from top to bottom, making it look very jumpy and not the ideal result.

Note: the cells are dynamic depending on the size of the message text

Anyone come across this? Any help would be great.

Thanks

This isn't really a Swift question, so it would be better asked over on forums.developer.apple.com.

The short answer is that reloadData, and the redisplay resulting from the reload are both handled asynchronously by the table view. When you add scrolling to that mix, you can't really ensure that everything happens in the proper order.

The best solution is to avoid using reloadData (or any of the reload… methods), but use the "insertRows(at:with:)" method instead. You may additionally need to defer the scrolling function to the next iteration of the run loop.

Thanks for the response Quincey.

Managed to figure it out, for anyone else:

Implement this:

var cellHeights: [IndexPath: CGFloat] = [:]

        ///* Dynamic Cell Sizing *///
    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        ///For every cell, retrieve the height value and store it in the dictionary
        cellHeights[indexPath] = cell.frame.size.height
    }

override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return cellHeights[indexPath] ?? 70.0
}