I create a table view that every time I scroll to the end of table it will show shimmer in table section 1 for waiting the api load a new data. After api finish load data, new data will append to the array that use for contain all data that be show to table view on section 0, then reload the table view to update the section 1 numberOfRowsInSection to 0 to hide the shimmer and update the section 0 numberOfRowsInSection
So this is the example of my code
fileprivate var data = [dataArray]() {
didSet {
guard !data.isEmpty else {
return
}
tableView.reloadData()
tableView.layoutIfNeeded()
view.layoutIfNeeded()
}
}
fileprivate var isLoadingMore: Bool = false {
didSet {
tableView.reloadSections(IndexSet(integer: 1), with: .automatic)
tableView.layoutIfNeeded()
tableViewHeightConstraint.constant = tableView.contentSize.height + 60.0
view.layoutIfNeeded()
}
}
fileprivate func loadData() {
if let size = self.paging.totalSize,
data.count >= size {
return
}
let limit = paging.limit
let offset = paging.offset
guard !isLoadingMore else { return }
isLoadingMore = true
controller.requestContent(
completion: { [weak self] (success, offset, size, data) in
DispatchQueue.main.async {
self?.isLoadingMore = false
guard let list = data,
let data = list as? [dataArray],
let size = size else {
return
}
if success {
if self?.paging.currentPage == 0 {
self?.data = data
if self?.scrollView.frame.size.height >= self?.scrollView.contentSize.height {
self?.paging.totalSize = size
self?.paging.currentPage += 1
self?.loadData()
return
}
} else {
self?.data.append(contentsOf: songs)
}
self?.paging.totalSize = size
self?.paging.currentPage += 1
} else {
self?.alert("failed")
}
}
})
}
fileprivate func loadDataFromCoreData() {
isLoadingMore = false
let context = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
let dataFromCoreData = Datas.fetchData(context: context).filter({$0.isSaved})
songs = dataFromCoreData.map({ dataArray(song: $0) })
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return data.count
case 1:
return isLoadingMore ? 1 : 0
default:
return 0
}
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if ((scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height){
loadData()
}
}
func setupForCeckingAvailableData() {
utility.checkInternetAccess = { [weak self] result in
if result {
self?.paging = Paging()
self?.loadData()
} else {
self?.loadDataFromCoreData()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
setupForCeckingAvailableData()
}
so some time when I first time load or try fetch new data by scrolling to the end of table I got a crash with the message is
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (10), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
So what the cause of it? Why got that crash even though I already use reloadData()
every time I append a new data to variable data
. Should I change reloadData()
to
tableView.beginUpdates()
tableView.insertRows(at: indexPaths, with: .automatic)
tableView.endUpdates()
? if that so, is that the crash cause insertRows
only refresh specific row and section so no take a loot of time to refresh table with a loot of datas??
That's all of my question, Thank you