¿Hay alguna forma de averiguar cuándo UITableView
ha terminado de solicitar datos de su fuente de datos?
Ninguno de los viewDidLoad
/ viewWillAppear
/ viewDidAppear
métodos del controlador de vista asociado (UITableViewController
) es útil aquí, ya que todos se activan demasiado pronto. Ninguno de ellos (enteramente comprensible) garantiza que las consultas a la fuente de datos hayan finalizado por el momento (por ejemplo, hasta que se desplace la vista).
Una solución que he encontrado es que llamar reloadData
en viewDidAppear
, ya que, cuando reloadData
regresa, la vista de tabla está garantizado de haber terminado la consulta de la fuente de datos tanto como lo necesita por el momento.
Sin embargo, esto parece bastante desagradable, ya que supongo que está provocando que se solicite la misma información a la fuente de datos dos veces (una vez automáticamente y otra debido a la reloadData
llamada) cuando se carga por primera vez.
La razón por la que quiero hacer esto es que quiero preservar la posición de desplazamiento del UITableView
, pero hasta el nivel de píxel, no solo hasta la fila más cercana.
Al restaurar la posición de desplazamiento (usando scrollRectToVisible:animated:
), necesito que la vista de tabla ya tenga suficientes datos, o de lo contrario, la scrollRectToVisible:animated:
llamada al método no hace nada (que es lo que sucede si coloca la llamada por sí sola en cualquiera de viewDidLoad
, viewWillAppear
o viewDidAppear
).
fuente
Respuestas:
Esta respuesta ya no parece funcionar, debido a algunos cambios realizados en la implementación de UITableView desde que se escribió la respuesta. Ver este comentario: ¿ Recibir una notificación cuando UITableView haya terminado de solicitar datos?
He estado jugando con este problema para un par de días y creo que la subclasificación
UITableView
'sreloadData
es el mejor enfoque:reloadData
no termina antes de que la tabla haya terminado de recargar sus datos. Entonces, cuando el segundoNSLog
se activa , la vista de tabla ha terminado de solicitar datos.He subclasificado
UITableView
para enviar métodos al delegado antes y despuésreloadData
. Funciona a las mil maravillas.fuente
reloadData
regresa inmediatamente y veo "END reloadData" antes de que las celdas se vuelvan a cargar (es decir, antes deUITableViewDataSource
llamar a los métodos). Mi experimentación demuestra exactamente lo contrario de lo que dices. Debo entender mal lo que estás tratando de decir.[super reloadData]
funciona para mí:dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"reload complete");});
. Básicamente, salta los bloques que se publican en la vista de tablareloadData
.Tuve un mismo escenario en mi aplicación y pensé en publicar mi respuesta para ustedes, ya que otras respuestas mencionadas aquí no funcionan para mí para iOS7 y versiones posteriores.
Finalmente, esto es lo único que funcionó para mí.
Actualización rápida:
Entonces, ¿cómo funciona esto?
Básicamente, cuando realizas una recarga, el subproceso principal se vuelve ocupado, por lo que en ese momento cuando hacemos un envío de subproceso asíncrono, el bloque esperará hasta que el subproceso principal termine. Entonces, una vez que la vista de tabla se haya cargado por completo, el hilo principal terminará y enviará nuestro bloque de método
Probado en iOS7 e iOS8 y funciona increíble;)
Actualización para iOS9: esto funciona bien en iOS9 también. He creado un proyecto de muestra en github como POC. https://github.com/ipraba/TableReloadingNotifier
Adjunto la captura de pantalla de mi prueba aquí.
Entorno probado: simulador iOS9 iPhone6 de Xcode7
fuente
EDITAR: Esta respuesta en realidad no es una solución. Probablemente parece funcionar al principio porque la recarga puede suceder bastante rápido, pero de hecho, el bloque de finalización no se llama necesariamente después de que los datos hayan terminado de recargarse por completo, porque reloadData no se bloquea. Probablemente debería buscar una mejor solución.
Para ampliar la respuesta de @Eric MORAND, pongamos un bloque de finalización. ¿A quién no le encanta un bloque?
y...
Uso:
fuente
dispatch_async(dispatch_get_main_queue(), ^{completionBlock();});
. Básicamente, esto salta los bloques publicados por la vista de tabla enreloadData
.reloadData solo solicita datos para las celdas visibles. Dice, para recibir una notificación cuando se cargue una parte específica de su tabla, conecte el
tableView: willDisplayCell:
método.fuente
Esa es mi solucion. 100% funciona y se utiliza en muchos proyectos. Es una subclase simple de UITableView.
Es similar a la solución de Josh Brown con una excepción. No se necesita ningún retraso en el método performSelector. No importa cuánto tiempo
reloadData
tarde.tableViewDidLoadData:
Siempre dispara cuandotableView
termina de preguntardataSource
cellForRowAtIndexPath
.Incluso si no desea crear una subclase
UITableView
, simplemente puede llamar[performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f]
y se llamará a su selector justo después de que la tabla termine de recargarse. Pero debe asegurarse de que se llame al selector solo una vez por llamada areloadData
:Disfrutar. :)
fuente
performSelector
o la ejecución en el hilo principaldispatch_asynch
no funcionan en iOS 9 .Esta es una respuesta a una pregunta ligeramente diferente: también necesitaba saber cuándo
UITableView
había terminado de llamarcellForRowAtIndexPath()
. Me subclaseslayoutSubviews()
(gracias @Eric MORAND) y se añadió una devolución de llamada delegado:SDTableView.h:
SDTableView.m:
Uso:
MyTableViewController.h:
MyTableViewController.m:
NOTAS: Dado que esta es una subclase de la
UITableView
cual ya tiene una propiedad de delegado que apunta,MyTableViewController
no es necesario agregar otra. El "delegado @dynamic" le dice al compilador que use esta propiedad. (Aquí hay un enlace que describe esto: http://farhadnoorzay.com/2012/01/20/objective-c-how-to-add-delegate-methods-in-a-subclass/ )La
UITableView
propiedad enMyTableViewController
debe cambiarse para usar la nuevaSDTableView
clase. Esto se hace en el Inspector de identidad de Interface Builder. Seleccione elUITableView
interior delUITableViewController
y establezca su "Clase personalizada" enSDTableView
.fuente
Encontré algo similar para recibir una notificación de cambio
contentSize
deTableView
. Creo que eso también debería funcionar aquí, ya que contentSize también cambia con la carga de datos.Prueba esto:
Por
viewDidLoad
escrito,y agregue este método a su viewController:
Es posible que necesite pequeñas modificaciones en la verificación de cambios. Sin embargo, esto me había funcionado.
¡Salud! :)
fuente
-viewWillAppear
y elimínese en el-viewWillDisapear
método.Aquí hay una posible solución, aunque es un truco:
Donde su
-scrollTableView
método se desplaza por la vista de tabla con-scrollRectToVisible:animated:
. Y, por supuesto, puede configurar el retraso en el código anterior de 0.3 a lo que parezca funcionar para usted. Sí, es ridículamente hacky, pero me funciona en mi iPhone 5 y 4S ...fuente
Creo que tuve algo similar. Agregué un BOOL como variable de instancia que me dice si el desplazamiento se ha restaurado y lo verifico
-viewWillAppear:
. Cuando no se ha restaurado, lo restauro en ese método y configuro el BOOL para indicar que recuperé el desplazamiento.Es una especie de truco y probablemente se pueda hacer mejor, pero esto funciona para mí en este momento.
fuente
-viewDidLoad
(donde debería suceder, por supuesto) pero eso solo funcionó cuando configuré el desplazamiento animado. Al mover la configuración del desplazamiento-viewWillAppear:
funcionó, pero tuve que mantener una bandera para configurarlo solo una vez. Supongo que la vista de tabla recarga sus datos una vez agregados a una vista, por lo que ya está en-loadView
. ¿Está seguro de que tiene sus datos disponibles al cargar la vista? ¿O se está cargando en un hilo separado o algo así?Parece que desea actualizar el contenido de la celda, pero sin los saltos repentinos que pueden acompañar a las inserciones y eliminaciones de celdas.
Hay varios artículos sobre cómo hacerlo. Este es uno.
Sugiero usar setContentOffset: animated: en lugar de scrollRectToVisible: animated: para configuraciones de píxeles perfectos de una vista de desplazamiento.
fuente
Puedes probar la siguiente lógica:
Y antes de llamar a reloadData, establezca prevIndexPath en nil. Me gusta:
Probé con NSLogs y esta lógica parece estar bien. Puede personalizar / mejorar según sea necesario.
fuente
finalmente he hecho que mi código funcione con esto -
había pocas cosas que debían ser atendidas -
- (UITableViewCell *)MyTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
"fuente
Puede cambiar el tamaño de su vista de tabla o establecer el tamaño del contenido en este método cuando se cargan todos los datos:
fuente
Simplemente ejecuto el temporizador programado repetido y lo invalido solo cuando el contentSize de la tabla es mayor cuando la altura tableHeaderView (significa que hay contenido de filas en la tabla). El código en C # (monotouch), pero espero que la idea sea clara:
fuente
¿No se
UITableView
layoutSubviews
llama justo antes de que la vista de tabla muestre su contenido? He notado que se llama una vez que la vista de tabla ha terminado de cargar sus datos, tal vez debería investigar en esa dirección.fuente
Desde iOS 6 en adelante, el
UITableview
método delegado llamó:se ejecutará una vez que su mesa se recargue correctamente. Puede realizar la personalización según sea necesario en este método.
fuente
La mejor solución que encontré en Swift
fuente
¿Por qué no simplemente extender?
desplácese hasta el final:
No probado con muchos datos
fuente