Michael Williams Michael Williams - 2 months ago 10
iOS Question

Delegate function from protocol not being called

I have a previously working delegate and protocol that since the conversion to Swift 3 is no longer being called.

protocol TaskCellDelegate {
func doneHit(_ cell : TaskCell)
}

class TaskCell : UITableViewCell {

var delegate : TaskCellDelegate?

@IBOutlet weak var label: UILabel!
@IBOutlet weak var detailLabel: UILabel!
@IBOutlet weak var _checkBox: M13Checkbox!


override func awakeFromNib() {
super.awakeFromNib()
let tap = UITapGestureRecognizer(target: self, action: #selector(TaskCell.buttonClicked(_:)))
tap.numberOfTapsRequired = 1
_checkBox.addGestureRecognizer(tap)
_checkBox.isUserInteractionEnabled = true
_checkBox.markType = .checkmark
_checkBox.boxType = .circle
_checkBox.stateChangeAnimation = .expand(.fill)
}
func buttonClicked(_ sender:UITapGestureRecognizer) {
delegate?.doneHit(self)
}
}


As you can see, when the _checkBox is tapped it should call the function doneHit in my class (not added because it doesn't seem necessary but I can) but I set a breakpoint and it's never called. I've set my delegate and conformed to the protocol in my class but nothing is happening. The doneHit function is supposed to update my backend but its not being called. If you need more info, I can provide.

Edit 1:

class TasksTVC: UITableViewController, TaskCellDelegate {

func doneHit(_ cell:TaskCell) {
if let indexPath = self.tableView.indexPath(for: cell) {
task = tasksInSectionArray[indexPath.section][indexPath.row]
if task.done == false {
cell._checkBox.setCheckState(.checked, animated: true)
task.done = true
task.completedBy = user
cell.detailLabel.text = "Completed By: \(task.completedBy)"
cell.label.textColor = UIColor.gray
print("cell checked")
}
else {
cell._checkBox.setCheckState(.unchecked, animated: true)
task.done = false
task.completedBy = ""
cell.detailLabel.text = ""
cell.label.textColor = UIColor.black
print("cell unchecked")

}
fb.updateTaskDoneBool(ref, taskID: task.id, taskDone: task.done)
fb.updateTaskCompletedBy(ref, taskID: task.id, taskCompletedBy: task.completedBy)
}

}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell
cell.selectionStyle = .none
task = tasksInSectionArray[indexPath.section][indexPath.row]
cell.label.text = task.title
if task.done == true {
cell._checkBox.setCheckState(.checked, animated: true)
cell.detailLabel.text = "Completed By: \(task.completedBy)"
cell.label.textColor = UIColor.gray
}
else {
cell._checkBox.setCheckState(.unchecked, animated: true)
cell.detailLabel.text = ""
cell.label.textColor = UIColor.black

}
doneHit(cell)
cell.delegate = self
return cell
}}

Answer

Looks like you didn't set correctly the delegate property in your TaskCell instance , I will make a very basic example hopefully it helps you to catch the issue:

Result (Edited)

Code

TableViewController

import UIKit

protocol TaskCellDelegate {
  func doneHit(_ cell: TaskCell)
}

class TableViewController: UITableViewController, TaskCellDelegate {
  func doneHit(_ cell: TaskCell) {
    let alert = UIAlertController(
                    title: "Info",
                    message: "button touched in cell",
                    preferredStyle: .alert
                )
    present(alert, animated: true, completion: nil)
  }
}

extension TableViewController {
  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 1
  }

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TaskCell
    cell.delegate = self // probably you forgot to set this part?

    return cell
  }
}

TaskCell (Edited)

Instead creating a new UITapGestureRecognizer to attach to the checkbox, you can use addTarget method to attach event handler for the UIControlEvents.valueChanged value.

import UIKit
import M13Checkbox

class TaskCell: UITableViewCell {

  var delegate: TaskCellDelegate?

  @IBOutlet weak var checkbox: M13Checkbox!

  override func awakeFromNib() {
    super.awakeFromNib()

    checkbox.addTarget(self, action: #selector(buttonClicked), for: .valueChanged)
  }


  func buttonClicked() {
    delegate?.doneHit(self)
  }

}