Para saber cuándo una vista de tabla termina de cargar su contenido, primero debemos tener una comprensión básica de cómo se muestran las vistas en la pantalla.
En el ciclo de vida de una aplicación, hay 4 momentos clave:
- La aplicación recibe un evento (toque, temporizador, bloque enviado, etc.)
- La aplicación maneja el evento (modifica una restricción, inicia una animación, cambia el fondo, etc.)
- La aplicación calcula la nueva jerarquía de vistas.
- La aplicación representa la jerarquía de vistas y la muestra
Las 2 y 3 veces están totalmente separadas. Por qué ? Por razones de rendimiento, no queremos realizar todos los cálculos del momento 3 cada vez que se realiza una modificación.
Entonces, creo que te enfrentas a un caso como este:
tableView.reloadData()
tableView.visibleCells.count // wrong count oO
¿Qué pasa aquí?
Como cualquier vista, una vista de tabla recarga su contenido de forma perezosa. En realidad, si llama reloadData
varias veces, no creará problemas de rendimiento. La vista de tabla solo vuelve a calcular su tamaño de contenido en función de su implementación delegada y espera el momento 3 para cargar sus celdas. Esta vez se llama pase de diseño.
Bien, ¿cómo entrar en el pase de diseño?
Durante el pase de diseño, la aplicación calcula todos los fotogramas de la jerarquía de vistas. Para involucrarse, puede anular los métodos dedicados layoutSubviews
, updateLayoutConstraints
etc. en UIView
ay los métodos equivalentes en una subclase de controlador de vista.
Eso es exactamente lo que hace una vista de tabla. Anula layoutSubviews
y, según la implementación de su delegado, agrega o elimina celdas. Llama cellForRow
justo antes de agregar y diseñar una nueva celda, willDisplay
justo después. Si llamó reloadData
o agregó la vista de tabla a la jerarquía, la vista de tablas agrega tantas celdas como sea necesario para llenar su marco en este momento clave.
Bien, pero ahora, ¿cómo saber cuándo una vista de tablas ha terminado de recargar su contenido?
Ahora podemos reformular esta pregunta: ¿cómo saber cuándo una vista de tabla ha terminado de presentar sus subvistas?
• La forma más fácil es acceder al diseño de la vista de tabla:
class MyTableView: UITableView {
func layoutSubviews() {
super.layoutSubviews()
// the displayed cells are loaded
}
}
Tenga en cuenta que este método se llama muchas veces en el ciclo de vida de la vista de tabla. Debido al desplazamiento y al comportamiento de la vista de tabla, las celdas se modifican, eliminan y agregan con frecuencia. Pero funciona, justo después de que las super.layoutSubviews()
células se cargan. Esta solución es equivalente a esperar el willDisplay
evento de la última ruta de índice. Este evento se llama durante la ejecución layoutSubviews
de la vista de tabla para cada celda agregada.
• Otra forma es recibir una llamada cuando la aplicación finalice un pase de diseño.
Como se describe en la documentación , puede usar una opción de UIView.animate(withDuration:completion)
:
tableView.reloadData()
UIView.animate(withDuration: 0) {
// layout done
}
Esta solución funciona pero la pantalla se actualizará una vez entre el momento en que se realiza el diseño y el momento en que se llama al bloque. Esto es equivalente a la DispatchMain.async
solución pero especificado.
• Alternativamente, preferiría forzar el diseño de la vista de tabla
Hay un método dedicado para forzar a cualquier vista a calcular inmediatamente sus marcos de subvista layoutIfNeeded
:
tableView.reloadData()
table.layoutIfNeeded()
// layout done
Sin embargo, tenga cuidado, al hacerlo se eliminará la carga diferida utilizada por el sistema. Llamar a esos métodos repetidamente podría crear problemas de rendimiento. Asegúrese de que no se les llame antes de que se calcule el marco de la vista de la tabla, de lo contrario, la vista de la tabla se cargará nuevamente y no se le notificará.
Creo que no hay una solución perfecta. Subclasificar las clases podría conducir a problemas. Un pase de diseño comienza desde la parte superior y va hacia la parte inferior, por lo que no es fácil recibir una notificación cuando se realiza todo el diseño. Y layoutIfNeeded()
podría crear problemas de rendimiento, etc. Pero conociendo esas opciones, debería poder pensar en una alternativa que se ajuste a sus necesidades.