title: Swift UITableView numberOfRows Error When Added or Removing Rows in Section
body: <p>I've been experiencing a very annoying issue this week. I have a UITableView that generates a number of sections (with section headers), each section always having 3 rows.</p>
  
  <p>I've implemented a hiding/showing section functionality when a section header is tapped, where all the rows in that section are either deleted or inserted accordingly. Everything works perfectly fine and as expected... 70% of the time. I find that once I start dragging around the UITableView a bit while tapping on headers and just being all around random, it crashes unexpectedly with the error: </p>
  
  <blockquote>
    <p>*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (3 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'</p>
  </blockquote>
  
  <p>Below is my relevant code:</p>
  
  <pre><code>    @IBOutlet var pastWinnersTableView: UITableView!
  
      var previousWeeks : [PreviousWeekData] = []
      var hiddenSections = Set&lt;Int&gt;()
      var firstTimeLoading = true ///This is needed to allow all the past week cells to start off as minimized
  
      //This function runs in response to a section header being tapped in the table view.
      @objc func expandCollapseSection(section: UIButton){
  
          pastWinnersTableView.isUserInteractionEnabled = false
  
          func indexPathsForSection() -&gt; [IndexPath] {
  
              var indexPaths = [IndexPath]()
  
              for row in 0..&lt;3 {
  
                  indexPaths.append(IndexPath(row: row, section: section.tag))
              }
  
                  return indexPaths
              }
  
          //If the section was previously hidden...
          if hiddenSections.contains(section.tag) {
                  hiddenSections.remove(section.tag)
                  pastWinnersTableView.insertRows(at: indexPathsForSection(), with: .fade)
  
  
          //If the section was previously showing...
          } else {
              hiddenSections.insert(section.tag)
              pastWinnersTableView.deleteRows(at: indexPathsForSection(), with: .fade)
          }
      }
  
  
      //MARK: - REQUIRED METHODS
      func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
  
          if firstTimeLoading == true || self.hiddenSections.contains(section) { return 0 }
  
              else { return 3 }
      }
  
      func numberOfSections(in tableView: UITableView) -&gt; Int {
  
          let numberOfPreviousWeeks = previousWeeks.count
  
          if numberOfPreviousWeeks &gt; 0 {return numberOfPreviousWeeks} else {return 0}
      }
  
      func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -&gt; UIView? {
  
          let weekNumber = previousWeeks[section].weekNumber
  
          let headerButton = UIButton(type: .custom)
              headerButton.layer.borderWidth = 1
              headerButton.layer.borderColor = UIColor.black.cgColor
              headerButton.layer.cornerRadius = 10
              headerButton.layer.masksToBounds = true
              headerButton.titleLabel?.font = UIFont(name: "Mouse Memoirs", size: 30)
              headerButton.backgroundColor = task.hexStringToUIColor(hex: "5B3F22")
              headerButton.setTitleColor(.white, for: .normal)
              headerButton.titleLabel?.shadowColor = .black
              headerButton.titleLabel?.shadowOffset = CGSize(width: 1, height: 1)
              headerButton.addTarget(self, action: #selector(expandCollapseSection), for: .touchUpInside)
  
              headerButton.tag = section
              hiddenSections.insert(section)
              headerButton.setTitle("Week \(String(weekNumber))", for: .normal)
  
          return headerButton
      }
  
      //This footer is essentially just a small blank space.
      func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -&gt; UIView? {
  
          let footer = tableView.dequeueReusableCell(withIdentifier: "pastWinnersWeekFooterCell") as! PastWinnersWeekFooterCell
  
          return footer
      }
  
  
      func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -&gt; CGFloat { return 45 }
  
      func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -&gt; CGFloat { return 5 }
  
      func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -&gt; CGFloat { return UITableView.automaticDimension }
  
      func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -&gt; CGFloat { return 44 }
  
  
  
      //PreviousWeekData[(weekNumber, firstPlacePlayers[(username, score)], secondPlacePlayers[(username, score)], thirdPlacePlayers[(username, score)]), (weekNumber,...)]
      //This defines the tableViewCell that holds all 3 placement sections with all the winners for a given week 
      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
  
          let weekSection = indexPath.section
          let weekData = previousWeeks[weekSection]
  
          let cell = tableView.dequeueReusableCell(withIdentifier: "pastWinnersTableViewCell", for: indexPath) as! PastWinnersTableViewCell
  
          cell.thisWeeksData = weekData
          cell.winnersCollectionView.tag = indexPath.row
  
          cell.frame = tableView.bounds;
          cell.layoutIfNeeded()
          cell.winnersCollectionView.reloadData()
          cell.collectionViewHeight.constant = cell.winnersCollectionView.collectionViewLayout.collectionViewContentSize.height;
  
          return cell
      }
  </code></pre>
  
  <p>Any ideas why it would be crashing on me with that error only sometimes? (ie. once I start dragging it around a bit and THEN tapping on headers? Tapping on my section headers is always a 3 in, 3 out deal so I'm not sure why it's getting confused.</p>
  
  <p>Thanks for the help!</p>