[iOS 15]The tableView(_:numberOfRowsInSection:) is called before the numberOfSections(in tableView: UITableView)

my dataSource is empty, so it crash. it worked well in iOS 14

  • How do you set the dataSource of the table view? On the storyboard? Or setting it in viewDidLoad() with code?

Add a Comment

Replies

i just define the dataSource in the Class

  • I said the dataSource of the table view, so you should enclose this line: tableView.dataSource = self. Anyway, the reason of the crash may not be the one I had in mind. Can you show the complete code to reproduce the issue? Or, at least, the full code of EquipmentListVC and all the used types in it?

Add a Comment

You said:

i just define the dataSource in the Class

Are you also settings the tableView's datasource to this property?
(It looks like you aren't)

Otherwise...

For both functions, zero is a valid return value...
...so that suggests there may be a problem with the property you are accessing?

You said:

my dataSource is empty

It's not clear what you mean by this.
If it's really empty, isn't a crash an appropriate response?

• Are you sure that both methods are being called?
• Have you checked the Int value that they return?
• Are you checking to see that datasource[section] exists, before you reference it?!

you declare

var dataSource = [Merchant]()

So it is empty.

Then you should crash when calling dataSource[section] where section is zero.

I do not see where you populate the dataSource.

Thanks for your replies, finally i find if i set tableView.tableHeaderView, tableView.estimatedSectionHeaderHeight tableView.delegate = self and tableView.dataSource = self before setting tableView.frame, it will call numberOfRowsInSection first and get the Index out of range error.

Then i place tableView.delegate = self and tableView.dataSource = self below the tableView.frame, it calls numberOfSections first and do not call numberOfRowsInSection. Commenting one of the tableView.tableHeaderView and tableView.estimatedSectionHeaderHeight also work well.

this is the complete code.

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
   
  let dataSource = [[String]]()
   
  let tableView = UITableView(frame: .zero, style: .plain)

  override func viewDidLoad() {
    super.viewDidLoad()
     
    let bounds = UIScreen.main.bounds
     
    tableView.tableHeaderView = UIView()
//    tableView.tableFooterView = UIView()
    tableView.estimatedSectionHeaderHeight = 0
//    tableView.estimatedSectionFooterHeight = 0
     
    // before frame
    tableView.delegate = self
    tableView.dataSource = self
     
    tableView.frame = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height)
     
    // after frame
//      tableView.delegate = self
//      tableView.dataSource = self
     
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    view.addSubview(tableView)
  }
   
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return dataSource[section].count
  }
   
  func numberOfSections(in tableView: UITableView) -> Int {
    return dataSource.count
  }
   
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
    return cell
  }
}