Функция делегирования из протокола не вызывается

#ios #delegates #protocols #swift3

#iOS #делегаты #протоколы #swift3

Вопрос:

У меня есть ранее работавший делегат и протокол, который с момента преобразования в Swift 3 больше не вызывается.

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

Как вы можете видеть, когда нажата _checkBox, она должна вызывать функцию doneHit в моем классе (не добавлена, потому что это не кажется необходимым, но я могу), но я установил точку останова, и она никогда не вызывается. Я установил свой делегат и соответствовал протоколу в своем классе, но ничего не происходит. Функция doneHit должна обновлять мой серверный сервер, но она не вызывается. Если вам нужна дополнительная информация, я могу предоставить.

Редактировать 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
    }}
  

Комментарии:

1. buttonClicked вызывается? Покажите свой cellForRowAtindexPath метод.

Ответ №1:

Похоже, вы неправильно установили delegate свойство в своем TaskCell экземпляре, я приведу очень простой пример, надеюсь, это поможет вам уловить проблему:

Результат (отредактирован)

Код

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

Ячейка задачи (отредактирована)

Вместо создания нового UITapGestureRecognizer для прикрепления к флажку вы можете использовать addTarget метод для прикрепления обработчика событий к UIControlEvents.valueChanged значению.

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

Комментарии:

1. Это не учитывает, что я вызвал buttonClicked как действие в моем распознавателе жестов касания. Это означает, что у меня есть кнопка, созданная в IB, и я использую ее для запуска функции.

Ответ №2:

Существуют следующие случаи, если делегат не вызывается:

  1. Действие: buttonClicked не вызывается.
  2. Контроллер представления не соответствует протоколу.

     class ViewController: UIViewController, TaskCellDelegate {
      
  3. Метод протокола не реализован внутри контроллера представления.

     func doneHit(_ cell : TaskCell) {
        print("delegate implementation called")
    }
      
  4. Делегат не назначен в cellForRowAtIndexPathMethod:

     cell.delegate = self
      

Комментарии:

1. Пожалуйста, ознакомьтесь с изменениями. Я сделал все эти вещи. Вся эта ситуация работала просто отлично, прежде чем я выполнил переход на swift 3.