Search code examples
iosswiftuitableviewuipickerview

UIPickerView inside a Custom UITableViewCell not initialising, awakeFromNib() not being called


I'm trying to get a UIPickerView inside a custom UITableViewCell to load. The cell loads fine, and I'm able to pass the data (an array of strings) from the UITableViewController to the custom cell through a delegate but the picker just loads blank. I can't for the life of me figure out why.

This seems to be a similar issue but the suggested solution (namely to reload the components of the UIPickerView after setting the pickerData array in the cellForRowAt method) doesn't seem to work.

Any help or insights greatly appreciated.

Custom Cell with UIPickerView

class GradeSelectionCell: UITableViewCell, UIPickerViewDataSource, UIPickerViewDelegate, ReusableView {

    @IBOutlet var pickerView: UIPickerView!

    var pickerData = [String]()
    var numComponents = Int()    

    override func awakeFromNib() {

   // Initialization code

        self.pickerData = Array<String>()
        self.pickerView.delegate = self
        self.pickerView.dataSource = self
        super.awakeFromNib()

    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return numComponents
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
      return   pickerData.count
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        print(pickerData[row])
        return pickerData[row]
        }
    }

extension GradeSelectionCell: PickerSetupDelegate {
    func setupPicker(data: [String], numberOfCompents: Int){
        pickerData = data
        numComponents = numberOfCompents
        print("PickerSetupDelegate Called")
        print("pickerData \(String(describing: pickerData))")

    }
}

cellForRowAt

let cell = tableView.dequeueReusableCell(withIdentifier: "GradeSelectionCell", for: indexPath) as! GradeSelectionCell
cell.setupPicker(data: grades, numberOfCompents: 1)
// cell.pickerView.reloadAllComponents()
return cell

Registering Cell in viewDidLoad

tableView.register(GradeSelectionCell.self, forCellReuseIdentifier: "GradeSelectionCell")

Solution

  • You're registering the cell using the cell class initializer:

    func register(_ cellClass: AnyClass?, forCellReuseIdentifier identifier: String)
    

    But it seems you're trying initialize the cell from a xib. So you should be using the UINib initializer:

    func register(_ nib: UINib?, forCellReuseIdentifier identifier: String)
    

    e.g.

    tableView.register(UINib(nibName: "GradeSelectionCell", bundle: nil), forCellReuseIdentifier: "GradeSelectionCell"))
    

    (or whatever the filename of the xib you're using is).

    Otherwise, you're just loading an instance of the class directly without the user interface you laid out in the xib.

    Note, if you're using a cell defined in a storyboard in your controller's view, then it would already be registered and you do not need to register it again.

    And it's not crashing because you're never actually calling the pickerView property — awakeFromNib won't be called, and setupPicker just sets data. Presumably it crashes when you uncomment the line cell.pickerView.reloadAllComponents()?