¿Usar didSelectRowAtIndexPath o método prepareForSegue para UITableView?

101

Estoy usando guiones gráficos y tengo un UITableView. Tengo una configuración de segue que empuja desde mi tabla al VC detallado. Pero, ¿qué método debo usar para manejar esto? Tendré que pasar un par de objetos a la vista de detalles. ¿Pero uso didSelectRowAtIndexo -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender?

Jon
fuente

Respuestas:

199

Si utiliza prepareForSegue:sender: , no tendrá mucho que cambiar si luego decide activar la transición desde algún control fuera de la vista de tabla.

El prepareForSegue:sender:mensaje se envía al controlador de vista actual, por lo que sugeriría algo como esto:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Assume self.view is the table view
    NSIndexPath *path = [self.tableView indexPathForSelectedRow];
    DetailObject *detail = [self detailForIndexPath:path];
    [segue.destinationViewController setDetail:detail];
}

En Swift:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let path = self.tableView.indexPathForSelectedRow()!
    segue.destinationViewController.detail = self.detailForIndexPath(path)
}
Rob Mayoff
fuente
1
Ok, ¿puede dar un ejemplo de cómo implementarlo pasando un objeto basado en indexPath.
Jon
4
no debería self.viewestar solo senderaquí? Ni siquiera podía ir [self.view indexPathForSelectedRow]al trabajo, tenía que hacerlo[sender indexPathForSelectedRow];
ladookie
¿Cómo harías esto en Swift?
Usuario
@robmayoff Gracias por actualizar esto para Swift. Hice algunas ediciones leves para reflejar los cambios de idioma recientes. Espero que esto ayude a otros
Zack Shapiro
Es extraño que tableView.indexPathForSelectedRow()contenga el valor correcto cuando prepareFroSegue...se llama: tableView(_:didSelectrowAtIndexPath:)no se llama hasta más tarde.
Nicolas Miari
5

Hice esto y funcionó

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    NSLog(@"Row Selected = %i",indexPath.row);

    [self performSegueWithIdentifier:@"testID" sender:self.view];    
}
Rohit Mandiwal
fuente
11
Eso no tiene sentido. Debe usar el segue O el delegado de vista de tabla. Simplemente cree una transición desde la celda y automáticamente realizará lo mismo que hizo sin escribir código.
Yariv Nissim
3
¿Cómo se asigna un segue a una celda sin didSelectRow?
Mork desde el
3

Cuando el remitente es UITableViewCell, puede pedirle a UITableView que consulte indexPath de la celda.

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if let cell = sender as? UITableViewCell {
            let indexPath = self.tableView.indexPathForCell(cell)!
            assert(segue.destinationViewController.isKindOfClass(DetailViewController))
            let detailViewController = segue.destinationViewController as! DetailViewController
            detailViewController.item = self.items[indexPath.row] // like this
        }
    }
Kaz Yoshikawa
fuente
1

si su propiedad tableView está en otra clase y solo tiene una sección , entonces podría usar la tagpropiedad para almacenar la fila de la celda como:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];

     cell.tag = indexPath.row;

     return cell;
}

Y luego puede acceder a él ya que senderes la misma celda con el valor de la fila en su etiqueta:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    MyDestinationViewController *destinationViewController = segue.destinationViewController;
    destinationViewController.myProperty = [tableViewElementsArray objectAtIndex:[sender tag]]; // sender will be your cell 
}
Laszlo
fuente
1

self.tableView.indexPathForSelectedRowdevuelve la celda seleccionada, pero no la celda del remitente, por ejemplo, la celda del remitente no está seleccionada (acción accesoria), o en caso de selección múltiple. La mejor manera es obtener indexPath para segue sender:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    __auto_type itemViewController = (id<ItemViewController>)segue.destinationViewController;
    itemViewController.senderIndexPath = [self.tableView indexPathForCell:sender];
}

En Swift:

protocol ItemViewController {
    var senderIndexPath : IndexPath? { get set }
    var selectedIndexPaths : [IndexPath]? { get set }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if  let cell = sender as? UITableViewCell,
        var itemViewController = segue.destination as? ItemViewController {
        itemViewController.senderIndexPath = tableView.indexPath(for: cell)
        itemViewController.selectedIndexPaths = tableView.indexPathsForSelectedRows
    }
}
Stanislav P.
fuente
0

Si lo usa prepareForSegue:, puede verificar quién es el remitente y ejecutar un código diferente

Por ejemplo en Swift

override func prepareForSegue(segue: UiStoryboardSegue, sender: AnyObject?)
{
   var senderIsTableviewCell:Bool! = sender?.isKindOfClass(UITableViewCell)

   if senderIsTableviewCell
   {
       //do something
   }
}
Eugenio
fuente
2
Solo hazlo: si deja tableViewCell = sender as? UITableViewCell {// haz algo} . Si el remitente no se puede convertir a UITableViewCell, "hacer algo" no se ejecutará.
mbeaty