Tengo una UIView dentro de un TableViewCell, cuando los usuarios hicieron tapping en esta UIView, se fue a otro controlador de vista y pasó datos.

Entonces, dentro de TableViewCellClass, hice lo siguiente:

Configuré un protocolo y detecté el gesto "Tap", cuando la tabla de usuario de la UIView. Esta parte está funcionando bien:

protocol MyDelegate : class {
        func runThisFunction(myString : String)
}

class MyTableViewCell: UITableViewCell {

        weak var delegate : MyDelegate?

        ...other code here

        //here detect the tap 
        let tap = UITapGestureRecognizer(target: self, action: #selector(hereTapped))
        self.myUIElementInThisCell.addGestureRecognizer(tap)

}

@objc func hereTapped(sender: UITapGestureRecognizer? = nil){
    self.delegate?.runThisFunction(myString: "I am a man")
}

Entonces, en mi controlador de vista que contiene este TableView, hice lo siguiente:

Extiendo el MyDelegate como subclase, y luego adjunto la función de protocolo dentro de él como a continuación

class MyViewController: UIViewController,MyDelagate{

func runThisFunction(myString : String) {
     print("Tapped in view controller")
    self.performSegue(withIdentifier: "MySegue",sender : self)
}

 override func viewDidLoad() {
    super.viewDidLoad()

    let tableViewCell = MyTableViewCell()
    tableViewCell.delegate = self
 }
}

Resultado:

Después de hacer todo lo anterior, cuando toqué el UIView, no realizó la segue como se indica en MyViewControllerClass, incluso el comando print() tampoco se ejecutó.

Entonces, ¿qué me estoy perdiendo? Por favor, dame una solución. Gracias

0
ken 2 mar. 2018 a las 15:46

4 respuestas

La mejor respuesta

El problema está en tu viewDidLoad:

// you create a new cell
let tableViewCell = MyTableViewCell()
// set its delegate
tableViewCell.delegate = self
// and then the cell is not used for anything else

Básicamente, no está configurando el delegado para las celdas que se presentan, sino para otra instancia que cree en viewDidLoad.

Debe establecer un delegado en cellForRowAt para asegurarse de que las celdas adecuadas obtengan el conjunto delegate:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "yourIdentifier", for: indexPath) as! MyTableViewCell
    cell.delegate = self
    return cell
}

Esto establecerá el delegate para esas celdas que se presentan.


Alternativamente, recomendaría usar didSelectRowAt de UITableViewDelegate (si su MyViewController lo implementa):

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.row == 0 { // only if it is the first cell (I assume that MyTableViewCell is first)
        runThisFunction(myString: "I am a man")
    }
}
0
Milan Nosáľ 2 mar. 2018 a las 13:39

El problema es que el delegado para instancias MyTableViewCell no está definido.

Cuando lo haga:

override func viewDidLoad() {
    super.viewDidLoad()

    let tableViewCell = MyTableViewCell()
    tableViewCell.delegate = self
}

Está configurando un delegado para un objeto que se destruirá justo cuando finalice el método viewDidLoad().

Solución 1

Para evitar esto, debe configurar el delegado dentro del método cellForRow.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as! MyTableViewCell
    cell.delegate = self

    // Other configurations

    return cell
}

Solución 2

También puede usar los métodos UITableViewDelegate para capturar la interacción del usuario con las celdas.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath)

    self.performSegue(withIdentifier: "MySegue",sender : self)
}

De esta manera, evitas todo lo MyDelegate protocol. Esta sería mi opción preferida.

1
nikano 2 mar. 2018 a las 13:04

La delegación no es muy buena aquí, de hecho, si desea cambiar el objeto que no pasó explícitamente a la celda.

Mi consejo es usar el cierre:

typealias CellTapHandler = (String)->()

class CustomCell: UITableViewCell {
    var handler: CellTapHandler?

    @objc func hereTapped(sender: UITapGestureRecognizer? = nil) {
        handler?("String or whatever you want to get back from cell.")
    }
    //...
}

Y configurarlo desde el controlador de vista

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "yourIdentifier", for: indexPath) 
    (cell as? MyTableViewCell).handler = { [weak self] string in  } 
    return cell
}

PD: Como dije, generalmente quieres pasar más objetos relacionados con la celda. Es difícil hacerlo con la delegación, ya que tuvo que pasar a la celda algún token adicional, para determinar el objeto por la celda, o pasar el objeto en sí mismo rompiendo el paradigma de separación Modelo-Vista. Pero se puede hacer fácilmente con cierres:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let object = self.myData[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: "yourIdentifier", for: indexPath) 
    (cell as? MyTableViewCell).handler = { [weak self] string in  
          self.performSegue(withIdentifier: "MySegue",sender : object)
    } 
    return cell
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     if (let myObj = sender as? MyObjType, let subsequentVC = segue.destination as? NextViewController) {
           subsequentVC.selectedMyObject = myObj
     }
}
0
MichaelV 2 mar. 2018 a las 13:22

El problema es que estas 2 líneas:

let tableViewCell = MyTableViewCell()
tableViewCell.delegate = self

No están relacionadas con las celdas mostradas en la tabla, es una celda creada sobre la marcha, por lo que

Establezca delegado en cellForRow para la celda en la que realmente esperará un disparador de delegado de ellos

 cell.delegate = self

Así

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

         let cell = areaSettTable.dequeueReusableCell(withIdentifier:cellID) as! MyTableViewCell
         cell.delegate = self
   }
1
Milan Nosáľ 3 mar. 2018 a las 07:34