Search code examples
iosswiftuipickerview

Swift: TextField not updating after selection from UIPickerView


I have created a controller that will give administrators the option to add new students to the database. I am trying to add a UIPicker to a textfield in a tableview that uses different custom cells.

The UIPicker pops up when I select the field, and it also returns all the data from my array. The problem is that my textfield is NOT being updated after selecting something from the UIPicker. A simple print to the console does however confirm that the selection works.

How do I correctly send my selection to the textfield that is linked to the UIPicker?

class AddStudentInfoController: UITableViewController, UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource {

@IBOutlet var addStudentGradeTextField: UITextField!

var pickerGrade = UIPickerView()
var allCellsText = [String]()

let firstNameCell = "firstNameCell"
let lastNameCell = "lastNameCell"
let gradeCell = "gradeCell"

var array = ["First Name", "Last Name", "Grade"]
var grade = ["--", "One", "Two", "Three"]

override func viewDidLoad() {
    super.viewDidLoad()

    pickerGrade.delegate = self
    pickerGrade.dataSource = self
    pickerGrade.backgroundColor = UIColor.white

    self.tableView.tableFooterView = UIView(frame: CGRect.zero)
    self.tableView.rowHeight = 60

    tableView.register(AddStudentFirstNameCell.self, forCellReuseIdentifier: firstNameCell)
    tableView.register(AddStudentLastNameCell.self, forCellReuseIdentifier: lastNameCell)
    tableView.register(AddStudentGradeCell.self, forCellReuseIdentifier: gradeCell)

}

// Load tableview
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return array.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    if indexPath.row == 0 {
        let cell = tableView.dequeueReusableCell(withIdentifier: firstNameCell, for: indexPath) as! AddStudentFirstNameCell

        cell.textLabel!.text = self.array[indexPath.row]
        cell.selectionStyle = UITableViewCellSelectionStyle.none

        return cell
    }

    else if indexPath.row == 1 {
        let cell = tableView.dequeueReusableCell(withIdentifier: lastNameCell, for: indexPath) as! AddStudentLastNameCell

        cell.textLabel!.text = self.array[indexPath.row]
        cell.selectionStyle = UITableViewCellSelectionStyle.none

        return cell
    }

    else {
        let cell = tableView.dequeueReusableCell(withIdentifier: gradeCell, for: indexPath) as! AddStudentGradeCell

        cell.textLabel!.text = self.array[indexPath.row]
        cell.selectionStyle = UITableViewCellSelectionStyle.none
        cell.addStudentGradeTextField?.inputView = pickerGrade

        return cell
    }
}

// Picker view
func textFieldDidBeginEditing(_ textField: UITextField) {
    pickerGrade.reloadAllComponents()
    pickerGrade.isHidden = false
}

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

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

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
    addStudentGradeTextField?.text = grade[row]
    self.view.endEditing(true)
}

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

// End editing
func textFieldDidEndEditing(_ textField: UITextField) {
    allCellsText.append(textField.text!)
}
}

All my custom cells for the tableview.

// #
// Custom cells for AddStudent.swift
// #
class AddStudentFirstNameCell: UITableViewCell {

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
    setupViews()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

let addStudentTextField: UITextField = {
    let addStudentTextField = UITextField()
    addStudentTextField.placeholder = "First Name"
    addStudentTextField.textColor = .red
    addStudentTextField.translatesAutoresizingMaskIntoConstraints = false
    addStudentTextField.rightViewMode = UITextFieldViewMode.always
    addStudentTextField.autocorrectionType = .no
    return addStudentTextField
}()

func setupViews() {

    addSubview(addStudentTextField)

    addStudentTextField.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 10).isActive = true
    addStudentTextField.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
    addStudentTextField.widthAnchor.constraint(equalToConstant: 150).isActive = true
    addStudentTextField.heightAnchor.constraint(equalToConstant: 48).isActive = true
}
}

class AddStudentLastNameCell: UITableViewCell {

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
    setupViews()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

let addStudentTextField: UITextField = {
    let addStudentTextField = UITextField()
    addStudentTextField.placeholder = "Last Name"
    addStudentTextField.textColor = .red
    addStudentTextField.translatesAutoresizingMaskIntoConstraints = false
    addStudentTextField.rightViewMode = UITextFieldViewMode.always
    addStudentTextField.autocorrectionType = .no
    return addStudentTextField
}()

func setupViews() {

    addSubview(addStudentTextField)

    addStudentTextField.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 10).isActive = true
    addStudentTextField.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
    addStudentTextField.widthAnchor.constraint(equalToConstant: 150).isActive = true
    addStudentTextField.heightAnchor.constraint(equalToConstant: 48).isActive = true
}
}

class AddStudentGradeCell: UITableViewCell {

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
    setupViews()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

let addStudentGradeTextField: UITextField! = {
    let addStudentGradeTextField = UITextField()
    addStudentGradeTextField.placeholder = "--"
    addStudentGradeTextField.textColor = .red
    addStudentGradeTextField.translatesAutoresizingMaskIntoConstraints = false
    addStudentGradeTextField.rightViewMode = UITextFieldViewMode.always
    addStudentGradeTextField.autocorrectionType = .no
    return addStudentGradeTextField
}()

func setupViews() {

    addSubview(addStudentGradeTextField)

    addStudentGradeTextField.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 10).isActive = true
    addStudentGradeTextField.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
    addStudentGradeTextField.widthAnchor.constraint(equalToConstant: 150).isActive = true
    addStudentGradeTextField.heightAnchor.constraint(equalToConstant: 48).isActive = true
}
}

Crash log

Starry`@objc AddStudentGradeCell.init(style : UITableViewCellStyle, reuseIdentifier : String?) -> AddStudentGradeCell:
0x10a402980 <+0>:   pushq  %rbp
0x10a402981 <+1>:   movq   %rsp, %rbp
0x10a402984 <+4>:   subq   $0x70, %rsp
0x10a402988 <+8>:   movq   %rdi, -0x28(%rbp)
0x10a40298c <+12>:  movq   %rcx, %rdi
0x10a40298f <+15>:  movq   %rdx, -0x30(%rbp)
0x10a402993 <+19>:  movq   %rsi, -0x38(%rbp)
0x10a402997 <+23>:  movq   %rcx, -0x40(%rbp)
0x10a40299b <+27>:  callq  0x10a46732a               ; symbol stub for: objc_retain
0x10a4029a0 <+32>:  movq   -0x40(%rbp), %rcx
0x10a4029a4 <+36>:  cmpq   $0x0, %rcx
0x10a4029a8 <+40>:  sete   %r8b
0x10a4029ac <+44>:  xorb   $-0x1, %r8b
0x10a4029b0 <+48>:  testb  $0x1, %r8b
0x10a4029b4 <+52>:  movq   %rax, -0x48(%rbp)
0x10a4029b8 <+56>:  jne    0x10a4029bc               ; <+60> at AddStudent.swift
0x10a4029ba <+58>:  jmp    0x10a4029dc               ; <+92> at AddStudent.swift
0x10a4029bc <+60>:  movq   -0x40(%rbp), %rdi
0x10a4029c0 <+64>:  callq  0x10a46747a               ; symbol stub for: static (extension in Foundation):Swift.String._unconditionallyBridgeFromObjectiveC (Swift.Optional<__ObjC.NSString>) -> Swift.String
0x10a4029c5 <+69>:  xorl   %esi, %esi
0x10a4029c7 <+71>:  movb   %sil, %r8b
0x10a4029ca <+74>:  movq   %rcx, -0x50(%rbp)
0x10a4029ce <+78>:  movq   %rax, -0x58(%rbp)
0x10a4029d2 <+82>:  movq   %rdx, -0x60(%rbp)
0x10a4029d6 <+86>:  movb   %r8b, -0x61(%rbp)
0x10a4029da <+90>:  jmp    0x10a4029f9               ; <+121> at AddStudent.swift
0x10a4029dc <+92>:  xorl   %eax, %eax
0x10a4029de <+94>:  movl   %eax, %ecx
0x10a4029e0 <+96>:  movb   $0x1, %dl
0x10a4029e2 <+98>:  movq   %rcx, %rsi
0x10a4029e5 <+101>: movq   %rcx, %rdi
0x10a4029e8 <+104>: movq   %rdi, -0x60(%rbp)
0x10a4029ec <+108>: movq   %rcx, -0x50(%rbp)
0x10a4029f0 <+112>: movq   %rsi, -0x58(%rbp)
0x10a4029f4 <+116>: movb   %dl, -0x61(%rbp)
0x10a4029f7 <+119>: jmp    0x10a4029f9               ; <+121> at AddStudent.swift
0x10a4029f9 <+121>: movb   -0x61(%rbp), %al
0x10a4029fc <+124>: movq   -0x50(%rbp), %rcx
0x10a402a00 <+128>: movq   -0x60(%rbp), %rdx
0x10a402a04 <+132>: movq   -0x58(%rbp), %rsi
0x10a402a08 <+136>: leaq   -0x20(%rbp), %rdi
0x10a402a0c <+140>: movq   %rsi, -0x20(%rbp)
0x10a402a10 <+144>: movq   %rdx, -0x18(%rbp)
0x10a402a14 <+148>: movq   %rcx, -0x10(%rbp)
0x10a402a18 <+152>: andb   $0x1, %al
0x10a402a1a <+154>: movb   %al, -0x8(%rbp)
0x10a402a1d <+157>: movq   -0x30(%rbp), %rcx
0x10a402a21 <+161>: movq   %rdi, -0x70(%rbp)
0x10a402a25 <+165>: movq   %rcx, %rdi
0x10a402a28 <+168>: movq   -0x70(%rbp), %rsi
0x10a402a2c <+172>: movq   -0x28(%rbp), %rdx
0x10a402a30 <+176>: callq  0x10a402680               ; Starry.AddStudentGradeCell.init (style : __C.UITableViewCellStyle, reuseIdentifier : Swift.Optional<Swift.String>) -> Starry.AddStudentGradeCell at AddStudent.swift:384
0x10a402a35 <+181>: addq   $0x70, %rsp exc_bad_instruction(code=exc_i386_invop,subcode=0x0)
0x10a402a39 <+185>: popq   %rbp
0x10a402a3a <+186>: retq   

Solution

  • I was able to fix my code by adding a very simple line of code.

    Wrong code:

    else {
        let cell = tableView.dequeueReusableCell(withIdentifier: gradeCell, for: indexPath) as! AddStudentGradeCell
    
        cell.textLabel!.text = self.array[indexPath.row]
        cell.selectionStyle = UITableViewCellSelectionStyle.none
    
        cell.addStudentGradeTextField?.inputView = pickerGrade
        cell.addStudentGradeTextField.placeholder = grade[0]
    
        return cell
    }
    

    Good code:

     else {
            let cell = tableView.dequeueReusableCell(withIdentifier: gradeCell, for: indexPath) as! AddStudentGradeCell
    
            cell.textLabel!.text = self.array[indexPath.row]
            cell.selectionStyle = UITableViewCellSelectionStyle.none
    
            cell.addStudentGradeTextField.inputView = pickerGrade
            cell.addStudentGradeTextField.placeholder = grade[0]
    
            addStudentGradeTextField = cell.addStudentGradeTextField
    
            return cell
        }