iosswiftxcodedelegatescustom-cell

Trying to use delegate to share text input from custom tableViewCell and Data is not sharing


I'm trying to use a delegate method to get data from custom cell button press into an array in ViewController.

The button works well, if let works well but data is not transferring from custom cell button press to ViewController array like I want it to...

I'm pretty new to coding still so I know I'm doing something wrong that's obvious. I'm applying the following from SO:

Getting Textfield Values from Custom Table View Cell

How to get user input from UItextfield and add it to an array?

My Custom cell:

import UIKit

class AddEntrantCell: UITableViewCell, UITextFieldDelegate {

var entrantName: ((String) -> Void)?
var entrantCompany: ((String) -> Void)?

@IBOutlet weak var entrantNameTextField: UITextField!
@IBOutlet weak var entrantCompanyTextField: UITextField!
@IBOutlet weak var addEntrant: UIButton!

var delegate: CellDelegate?

override func awakeFromNib() {
    super.awakeFromNib()
    entrantNameTextField.delegate = self
    entrantCompanyTextField.delegate = self
            
    if Global.uiMode == true {
        overrideUserInterfaceStyle = .light
    } else {
        overrideUserInterfaceStyle = .dark
    }
}

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

// Button press
@IBAction func addEntrantButton(_ sender: UIButton) {
    if let name = entrantNameTextField.text, let company = entrantCompanyTextField.text {
        delegate?.addEntrants(name: name, company: company)
    }
}
}

My VC with the tableView:

import UIKit

protocol CellDelegate {
func addEntrants(name: String, company: String)
}

class EntrySec: UIViewController, CellDelegate {

@IBOutlet weak var spaceStatus: UIButton!
@IBOutlet weak var entrantsTable: UITableView!

var entryGrid: [Entrant] = [
    Entrant(name: "", company: ""),
    Entrant(name: "Bob Lob", company: "Blue"),
    Entrant(name: "John Lon", company: "Red")
]

override func viewDidLoad() {
    super.viewDidLoad()
    entrantsTable.dataSource = self
    entrantsTable.register(UINib(nibName: Global.headerCellNibName, bundle: nil), forCellReuseIdentifier: Global.headerCellIdentifier)
    entrantsTable.register(UINib(nibName: Global.bodyCellNibName, bundle: nil), forCellReuseIdentifier: Global.bodyCellIdentifier)
    
    if Global.uiMode == true {
        overrideUserInterfaceStyle = .light
    } else {
        overrideUserInterfaceStyle = .dark
    }
}

func addEntrants(name: String, company: String) {
    entryGrid.append(Entrant(name: name, company: company)) // This does not work
    print("\(name)  \(company)")                            // This does not work
}
    
@IBAction func pauseSession(_ sender: UIButton) {
}
@IBAction func closeSession(_ sender: UIButton) {
}
@IBAction func menu(_ sender: UIButton) {
}
}

extension EntrySession: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return entryGrid.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.row == 0 {
        let addEntrantCell = entrantsTable.dequeueReusableCell(withIdentifier: Global.headerCellIdentifier, for: indexPath) as! AddEntrantCell
        addEntrantCell.entrantNameTextField.text = entryGrid[indexPath.row].name
        addEntrantCell.entrantCompanyTextField.text = entryGrid[indexPath.row].company
        return addEntrantCell
    } else {
        let entrantCell = entrantsTable.dequeueReusableCell(withIdentifier: Global.bodyCellIdentifier, for: indexPath) as! EntrantCell
        entrantCell.textLabel?.text = entryGrid[indexPath.row].name
        if entrantCell.textLabel?.text == "" {
            entrantCell.backgroundColor = #colorLiteral(red: 0.9764705882, green: 0.4274509804, blue: 0, alpha: 1)
            entrantCell.alpha = 0.5
        }
        return entrantCell
    }
}
}

Solution

  • You have not set cell delegate inside the cellForRowAt. so you have to set CellDelegate inside the cellForRowAt method. Like this.

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.row == 0 {
            let addEntrantCell = entrantsTable.dequeueReusableCell(withIdentifier: Global.headerCellIdentifier, for: indexPath) as! AddEntrantCell
            addEntrantCell.delegate = self // <--- Add delegate here
            addEntrantCell.entrantNameTextField.text = entryGrid[indexPath.row].name
            addEntrantCell.entrantCompanyTextField.text = entryGrid[indexPath.row].company
            return addEntrantCell
        } else {
            let entrantCell = entrantsTable.dequeueReusableCell(withIdentifier: Global.bodyCellIdentifier, for: indexPath) as! EntrantCell
            entrantCell.textLabel?.text = entryGrid[indexPath.row].name
            if entrantCell.textLabel?.text == "" {
                entrantCell.backgroundColor = #colorLiteral(red: 0.9764705882, green: 0.4274509804, blue: 0, alpha: 1)
                entrantCell.alpha = 0.5
            }
            return entrantCell
        }
    }
    

    You can also use a closure instead of a delegate. (You have already added code but need some correction)

    Update your cell class with this and remove other closures.

    var entrants: ((String, String) -> Void)?
    
    @IBAction func addEntrantButton(_ sender: UIButton) {
        if let name = entrantNameTextField.text, let company = entrantCompanyTextField.text {
            entrants?(name, company)
        }
    }
    

    and inside the cellForRow method, instead of set delegate add this

    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.row == 0 {
            let addEntrantCell = entrantsTable.dequeueReusableCell(withIdentifier: Global.headerCellIdentifier, for: indexPath) as! AddEntrantCell
            addEntrantCell.entrants = { name, company in
                entryGrid.append(Entrant(name: name, company: company))
            } // <--- Here
        
    // Rest of the code here