1

learning protocols and delegates here but I'm having trouble getting this scenario to work. I have two buttons inside custom tableView Cell. I have a protocol method that I've put inside each button block. When I press the buttons the print statements fire indicating the buttons work but the protocols inside the VC do not fire.

Essentially I'm trying to get the indexPath.row inside each button press. But they both need to be separate and I don't want to use button tags.

I've tried the following:

Swift protocol delegate not being fired

https://stackoverflow.com/a/60315509/13945484

As well as other ways to send the cell path. I tried using a closure inside tableView cellForRowAt indexPath, this does work properly but does not allow two different buttons to fire. Note: I'm using the same configuration for one single button press in another cell and this works perfectly. I don't get what I'm doing wrong here.

The VC

import UIKit

protocol CellDelegate {
func addEntrants(name: String, company: String)
}
protocol InOutDelegate {
func markIN(cell: UITableViewCell)
func markOUT(cell: UITableViewCell)
}

class EntrySec: UIViewController, CellDelegate, InOutDelegate {

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

var entryGrid: [Entrant] = [Entrant(name: "", company: "")]
var entryStatusGrid: [Bool] = [false]

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)
}

func addEntrants(name: String, company: String) {
    entryGrid.append(Entrant(name: name, company: company))
    entryStatusGrid.append(false)
    entrantsTable.reloadData()                             // This works as it should
}                                                          // This does not work below

func markIN(cell: UITableViewCell) {
    if let indexpath = self.entrantsTable.returnIndexPath(cell: cell) {
                  print(indexpath)                        // This does not fire
            }
}

func markOUT(cell: UITableViewCell) {                     // Second button protocol
}                                                         // Also does not fire when tried

}

extension EntrySec: 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.delegate = self
        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.delegate? = self
        entrantCell.nameLabel.text = entryGrid[indexPath.row].name
        entrantCell.companyLabel.text = entryGrid[indexPath.row].company
        return entrantCell
    }
}
}

extension UITableView {
func returnIndexPath(cell: UITableViewCell) -> IndexPath?{
    guard let indexPath = self.indexPath(for: cell) else {
        return nil
    }
    return indexPath                                       // This is supposed to help
}
}

The Custom Cell:

import UIKit

class EntrantCell: UITableViewCell {

@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var companyLabel: UILabel!
@IBOutlet weak var inButton: UIButton!
@IBOutlet weak var outButton: UIButton!
@IBOutlet weak var inOutLabel: UILabel!

var delegate: InOutDelegate?
var buttonAction: ((_ sender: AnyObject) -> Int)?

override func awakeFromNib() {
    super.awakeFromNib()
    
    inButton.layer.cornerRadius = 10.0
    outButton.layer.cornerRadius = 10.0
    
    if Global.uiMode == true {
        overrideUserInterfaceStyle = .light
    } else {
        overrideUserInterfaceStyle = .dark
    }
}

// Attempt CHANGE

@IBAction func inButton(_ sender: UIButton) {
    delegate?.markIN(cell: self)
    print("in button pressed")            // Print statement fires
}

@IBAction func outButton(_ sender: UIButton) {
    delegate?.markOUT(cell: self)
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)
}
}
RobbB
  • 1,214
  • 11
  • 39
  • Curious if it matters, should I be declaring the protocols inside the custom cell? Or is it okay that I define them inside the VC. As far as my understanding goes, it does not matter where as long as delegates are set... – RobbB Jan 02 '21 at 23:52
  • 3
    Remove the ? from `entrantCell.delegate? = self`. Ie you just want `entrantCell.delegate = self` – Paulw11 Jan 03 '21 at 00:03
  • I can't believe how simple that was, I just racked my brains for hours over an extra ? MAN. Well I appreciate this, thanks Paul – RobbB Jan 03 '21 at 00:07
  • Because you unwrapped the optional and `delegate` was `nil` the assignment was skipped. – Paulw11 Jan 03 '21 at 00:10
  • Makes sense when someone who knows their stuff explains it :) – RobbB Jan 03 '21 at 00:25

1 Answers1

2

You have made one small typing mistake by adding the ? in entrantCell.delegate? = self. This is valid syntax, so the compiler doesn't complain, but you don't get the result you are after. You actually want entrantCell.delegate = self.

Your code conditionally unwraps delegate and since that property is initially nil, no assignment takes place. Effectively, your code says If entrantCell.delegate isn't nil, assign self to it.

Without the ?, the assignment is made unconditionally.

Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • I had the same problem not setting the delegate = self correctly in a collectionView Cell and this fixed it. Figured I would post a thank you and so future newbies would know this applies to collectionView as well as tableView – Daniel Patriarca Feb 04 '22 at 19:07