Oliver
Oliver

Reputation: 33

How to know when UITableView has completed reloadData?

My live app crashes with following. I've done a lot of search and I understand now that I've to ensure that table reloads before calling scrollToRow. I've seen many workaround but I'm not sure which one will actually work. I've tried calling scrollToRow on main thread or calling after a delay but that doesn't solve my problem. I've load more (pagination) implemented which get messed up if I use fix to call scrollToRow after a delay.

How do we fix this? How to know for sure that table has completed reloading?

This solution seems to be looking good but it didn't work for me. https://stackoverflow.com/a/18812830/11957965

As crash happens only on live app, I can't reproduce it during development testing so I wanted to make sure that I've a working fix.

Crash

[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:usingPresentationValues:]: section (0) beyond bounds (0).

Code

if result!.data!.items!.count > 0 {
    self.msgTable.reloadData()

    let lastIndexPath = IndexPath(row: 0, section: 0)
    self.msgTable.scrollToRow(at: lastIndexPath, at: UITableView.ScrollPosition.top, animated: false)
}

performBatchUpdates Solution

// This one crashes
if #available(iOS 11.0, *) {
    self.mesgTable.performBatchUpdates({
        let index = IndexPath(row: 0, section: 0)
        self.mesgTable.insertRows(at: [index], with: .none)
    }, completion: { (success) in
        if self.currentPage == 1 && self.dataSource.count > 0 {
            let lastIndexPath = IndexPath(row: 0, section: 0)
            self.mesgTable.scrollToRow(at: lastIndexPath, at: UITableView.ScrollPosition.top, animated: false)
        }
    })
} else {
    if self.currentPage == 1 && self.dataSource.count > 0 {
        let lastIndexPath = IndexPath(row: 0, section: 0)
        self.mesgTable.scrollToRow(at: lastIndexPath, at: UITableView.ScrollPosition.top, animated: false)
    }
}

Crash

** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (1) must be equal to the number of sections contained in the table view before the update (0), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).'

Upvotes: 0

Views: 2394

Answers (2)

Eyzuky
Eyzuky

Reputation: 1935

Instead of reloadData, you can use performBatchUpdates with completion handler. With this method you manually insert the items and control the IndexPaths. This way you can insert with animation and scroll in the completion with animation. Look at this doc for reference:

https://developer.apple.com/documentation/uikit/uitableview/2887515-performbatchupdates?language=objc

Upvotes: 1

Eyzuky
Eyzuky

Reputation: 1935

Try this approach:

Check if the table has the index path. If so, scroll. If not, dispatch for another 0.5 seconds later and try again. You can do this 2-3 times until it works.

I didn’t give the full code as I am answering from my phone, but it should be pretty easy to figure out

Upvotes: 0

Related Questions