0

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

Zouhair Sassi
  • 1,277
  • 1
  • 8
  • 27
Jan sebastian
  • 191
  • 3
  • 14

2 Answers2

0

I just want to point out something else. Generally speaking, Singletons are Evil and I avoid them like the plague.

This is a real big code smell and would advise you to stop using this type of code:

TableView.beginUpdates()
TableView.insertRows(at: indexPaths, with: .automatic)
TableView.endUpdates()

See What is so bad about singletons? there are many more blog posts about it.

0

after I do some research I found a clue. I add tableView.reloadData() before tableView.reloadSections(IndexSet(integer: 1), with: .automatic) because when I see the crashlytic crash happend at tableView.reloadSections(IndexSet(integer: 1), with: .automatic)

Jan sebastian
  • 191
  • 3
  • 14