¿Es posible actualizar un solo UITableViewCell en un UITableView?

182

Tengo una costumbre UITableViewusando UITableViewCells. Cada uno UITableViewCelltiene 2 botones. Al hacer clic en estos botones, cambiará una imagen UIImageViewdentro de la celda.

¿Es posible actualizar cada celda por separado para mostrar la nueva imagen? Cualquier ayuda es apreciada.

Mago de iOS
fuente

Respuestas:

323

Una vez que tenga el indexPath de su celda, puede hacer algo como:

[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPathOfYourCell, nil] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates]; 

En Xcode 4.6 y superior:

[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:@[indexPathOfYourCell] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates]; 

Puedes configurar lo que quieras como efecto de animación, por supuesto.

Romain
fuente
44
Nitpicking aquí, pero, por supuesto, si solo estuviera actualizando una sola celda, probablemente querría usar [NSArray arrayWithObject:]en su lugar.
Leo Cassarani
57
Además, en esta situación, los beginUpdatesy endUpdatesson innecesarios.
kubi
2
El OP no está animando nada, por lo que no es necesario llamar a las fechas de inicio / finalización
kubi
2
Mientras el método no diga obsoleto en la última versión pública de Xcode, todas las versiones de iOS deberían estar bien.
Alejandro Iván
1
@Supertecnoboff verdadero, pero en algún momento podría ser reemplazado o cambiará su comportamiento. Es mejor manejar las deprecaciones lo antes posible
Alejandro Iván
34

Intenté simplemente llamar -[UITableView cellForRowAtIndexPath:], pero eso no funcionó. Pero, lo siguiente funciona para mí, por ejemplo. Yo allocy releaseel NSArraypara la gestión de la memoria apretada.

- (void)reloadRow0Section0 {
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    NSArray *indexPaths = [[NSArray alloc] initWithObjects:indexPath, nil];
    [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
    [indexPaths release];
}
ma11hew28
fuente
¿Es necesario [lanzamiento de indexPaths] aquí? Pensé que solo necesitabas eso si asignabas el objeto tú mismo.
powerj1984
44
Él asignó la matriz indexPaths. Pero la mejor pregunta es por qué piensa que es necesaria una "administración de memoria estricta". Autorelease hará el trabajo perfectamente bien aquí.
John Cromartie
22

Rápido:

func updateCell(path:Int){
    let indexPath = NSIndexPath(forRow: path, inSection: 1)

    tableView.beginUpdates()
    tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) //try other animations
    tableView.endUpdates()
}
Esqarrouth
fuente
¿Dónde llamar a este método?
Master AgentX
18

reloadRowsAtIndexPaths:está bien, pero aún obligará a los UITableViewDelegatemétodos a disparar.

El enfoque más simple que puedo imaginar es:

UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
[self configureCell:cell forIndexPath:indexPath];

Es importante invocar su configureCell:implementación en el subproceso principal, ya que no funcionará en un subproceso que no sea UI (la misma historia con reloadData/ reloadRowsAtIndexPaths:). A veces puede ser útil agregar:

dispatch_async(dispatch_get_main_queue(), ^
{
    [self configureCell:cell forIndexPath:indexPath];
});

También vale la pena evitar el trabajo que se realizaría fuera de la vista actualmente visible:

BOOL cellIsVisible = [[self.tableView indexPathsForVisibleRows] indexOfObject:indexPath] != NSNotFound;
if (cellIsVisible)
{
    ....
}
Maciek Czarnik
fuente
¿Por qué no quieres que se llame al delegado?
kernix
Este es el mejor enfoque, ya que no obliga a la vista de tabla a desplazarse hasta la parte superior en lugar de reloadRowsAtIndexPaths: o métodos reloadData.
ZviBar
Hice esto y terminé siendo atrapado por el hecho de que la celda fue reciclada
Travelling Man
16

Si está utilizando TableViewCells personalizados, el genérico

[self.tableView reloadData];    

no responde efectivamente esta pregunta a menos que abandone la vista actual y regrese. Tampoco la primera respuesta.

Para recargar con éxito su primera celda de vista de tabla sin cambiar de vista , use el siguiente código:

//For iOS 5 and later
- (void)reloadTopCell {
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    NSArray *indexPaths = [[NSArray alloc] initWithObjects:indexPath, nil];
    [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
}

Inserte el siguiente método de actualización que llama al método anterior para que pueda volver a cargar de forma personalizada solo la celda superior (o la vista de tabla completa si lo desea):

- (void)refresh:(UIRefreshControl *)refreshControl {
    //call to the method which will perform the function
    [self reloadTopCell];

    //finish refreshing 
    [refreshControl endRefreshing];
}

Ahora que tiene eso ordenado, dentro de su viewDidLoadagregar lo siguiente:

//refresh table view
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];

[refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];

[self.tableView addSubview:refreshControl];

Ahora tiene una función de tabla de actualización personalizada que volverá a cargar la celda superior. Para volver a cargar toda la tabla, agregue el

[self.tableView reloadData]; a su nuevo método de actualización.

Si desea volver a cargar los datos cada vez que cambia de vista, implemente el método:

//ensure that it reloads the table view data when switching to this view
- (void) viewWillAppear:(BOOL)animated {
    [self.tableView reloadData];
}
App Dev Guy
fuente
6

Swift 3:

tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
ergunkocak
fuente
4

Solo para actualizar estas respuestas ligeramente con la nueva sintaxis literal en iOS 6: puede usar Paths = @ [indexPath] para un solo objeto, o Paths = @ [indexPath1, indexPath2, ...] para varios objetos.

Personalmente, he encontrado que la sintaxis literal para matrices y diccionarios es inmensamente útil y ahorra mucho tiempo. Es más fácil de leer, por un lado. Y elimina la necesidad de un cero al final de cualquier lista de objetos múltiples, que siempre ha sido un bugaboo personal. Todos tenemos nuestros molinos de viento para inclinar, ¿sí? ;-)

Solo pensé en tirar esto en la mezcla. Espero eso ayude.

Gregory Hill
fuente
Di Greg, ¿cuál es realmente un ejemplo de esa sintaxis allí, por favor? ¡Gracias!
Fattie
3

Aquí hay una extensión UITableView con Swift 5:

import UIKit

extension UITableView
{    
    func updateRow(row: Int, section: Int = 0)
    {
        let indexPath = IndexPath(row: row, section: section)

        self.beginUpdates()
        self.reloadRows(at: [indexPath as IndexPath], with: UITableView.RowAnimation.automatic)
        self.endUpdates()
    }

}

Llamar con

self.tableView.updateRow(row: 1)
iphaaw
fuente
0

Necesito la celda de actualización pero quiero cerrar el teclado. Si yo uso

let indexPath = NSIndexPath(forRow: path, inSection: 1)
tableView.beginUpdates()
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) //try other animations
tableView.endUpdates()

el teclado desaparece


fuente