4

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
    }}
Michael Williams
  • 1,402
  • 2
  • 14
  • 27

2 Answers2

3

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)
  }
  
}
Community
  • 1
  • 1
Wilson
  • 9,006
  • 3
  • 42
  • 46
  • This doesn't take into consideration that I called buttonClicked as the action on my tap gesture recognizer. This implies that I have a button created in IB and am using that to fire off the function. – Michael Williams Oct 01 '16 at 15:31
0

There are following cases if delegate is not being called:

  1. The action: buttonClicked is not being called.
  2. The View Controller not Conforming to the protocol.

    class ViewController: UIViewController, TaskCellDelegate {
    
  3. The protocol method not implemented inside View Controller.

    func doneHit(_ cell : TaskCell) {
        print("delegate implementation called")
    }
    
  4. Delegate not assigned in cellForRowAtIndexPathMethod:

    cell.delegate = self
    
Bista
  • 7,869
  • 3
  • 27
  • 55