¿Cuál es el significado del mensaje “no index path for table cell are reused” en iOS 6/7?

Desde que comencé a comstackr mi aplicación con iOS 6 (y también iOS 7), comencé a ver este mensaje. Sé que la forma en que UITableViews trata de administrar las células es diferente en iOS 6, pero no he necesitado modificar mi código para que siga funcionando. Pero me preocupa que este mensaje pueda señalar algún problema potencial que aún no veo. ¿Alguien puede arrojar algo de luz?

Comencé a mostrar este error en el registro de iOS 7 beta 5 en adelante, incluido en iOS 7 GM / versión de lanzamiento, mientras que nunca lo había tenido en mi aplicación en iOS 6 o las versiones anteriores de iOS 7. Después de mucha experimentación, encontré la causa:

Estaba usando objetos UITableViewCell para las vistas de mi encabezado de sección y las tableView:viewForHeaderInSection: en tableView:viewForHeaderInSection: Esto parece ser una práctica común, especialmente desde iOS 5 cuando se hizo fácil diseñar una vista de encabezado de sección como una celda prototipo de vista de tabla en un StoryBoard con Interface Builder.

Cuando cambié mi aplicación para usar solo las subclases de UIView para mis vistas de encabezado de sección, los errores desaparecieron y, más importante aún, mi vista de tabla dejó de eliminar aleatoriamente encabezados de sección.

Parece que (desde iOS 7 beta 5) UITableView mantiene internamente una asignación de todos los objetos UITableViewCell en su jerarquía de vista y sus respectivas rutas de índice. Como un encabezado de sección (o un encabezado de vista de tabla del pie de página) no tiene una ruta de índice, si usa un objeto UITableViewCell para estas vistas, la vista de tabla se confundirá cuando encuentre un UITableViewCell para el que no tiene un ruta de índice, lo que da como resultado el error “sin ruta de índice para la celda de tabla que se está reutilizando” y, si no tiene suerte, muestra problemas técnicos en su vista de tabla:

ACTUALIZACIÓN : si tiene acceso a los foros de Apple Dev, aquí está el hilo (que comencé): https://devforums.apple.com/message/882042#882042

Como se sugiere en ese hilo, si no desea volver a factorizar mucho, puede crear un contenedor UIView alrededor de su UITableViewCell y devolverlo como la vista de encabezado de sección.

 UIView *view = [[UIView alloc] initWithFrame:[cell frame]]; [view addSubview:cell]; return view; 

Sin embargo, UIView cuenta que este enfoque “envoltorio” de UIView no funcionará bien con AutoLayout y rotación de dispositivos, por lo que le sugiero que use una subclase UIView para encabezado y pie de página, no una subclase UITableViewCell como se explica en la parte principal de la respuesta.

Devolvería el contentView de UITableViewCell en lugar de crear un wrapper … teniendo en cuenta el constraint-jabble en el storybord en mente

 return cell.contentView; 

Tuve el mismo problema y me llevó pocas horas cazar el problema. Resulta que estaba llamando [textField becomeFirstResponder] mientras configuraba las celdas (aquí el textField era parte de una tableviewcell personalizada); [textField becomeFirstResponder] por turnos publica la notificación de keyboardWillShow que a su vez causó que la tabla se cargara prematuramente, lo que provocó el infame mensaje de ” sin ruta de índice para la celda de tabla que se está reutilizando. ” Una vez que eliminé esa llamada, el problema desapareció.

Además de la respuesta aceptada (mluisbrown), necesitaba agregar un Masteringizing a la celda del encabezado, ya que el mío contenía una etiqueta de varias líneas, es decir,

 UIView *view = [[UIView alloc] initWithFrame:[cell frame]]; cell.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; [view addSubview:cell]; return view; 

Este es un error interno de UIKit, como se menciona en los propios foros de desarrollo de Apple. Supuestamente está corregido en las versiones más nuevas de xcode, aunque no pude encontrar información sobre qué versión corrige esto.

Como una adición a mi publicación anterior (en la que mencioné que esto aparentemente era un error con UIKit), pude encontrar una solución alternativa para mi caso particular (en la que el mensaje estaba relacionado con algunas fallas técnicas extrañas en la visualización de la tabla).

Aparentemente mi celda personalizada fue anulada -(void)setEditing:animated: mucho en regresar.

Mi código anterior era:

 - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [super setEditing:editing animated:animated]; [self someAdditionalCode]; } 

Pude solucionarlo cambiándolo a:

 - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [super setEditing:editing animated:animated]; // DRM: we want to perform the actions from this block in the main thread, but // asynchronously to avoid excessive delays which were causing issues. // dispatch_async(dispatch_get_main_queue(), ^void() { [self someAdditionalCode]; }); } 

Hacer mis endupdates después de resignfirstresponder resolvió mi problema (Tener un UITextFIeld en mi celda personalizada)

 -(void)textfieldEditDone { .... [textField resignFirstResponder]; [self.tableView endUpdates]; 

Tuve el mismo problema con el mensaje de error que aparece. Por lo que puedo ver, es causado al volver a cargar la vista de tabla desde una función llamada por el campo de texto como parte de su protocolo de delegado. Es decir textFieldDidEndEditing -> [controller.tableview reload …]

Para el registro, me encontré con este mensaje también cuando se ejecuta bajo iOS 6. Parece que algún código heredado o importado tenía algo como esto:

 (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section { NSInteger rows = 0; if ([delegate respondsToSelector:@selector(numberOfItemsInSection:)]) { rows = [delegate numberOfItemsInSection:section]; [tableView beginUpdates]; [tableView endUpdates]; } } 

Cuando se eliminó la secuencia beginUpdate: / endUpdate: el problema desapareció mágicamente.

Obviamente, esta es una pregunta antigua, pero con suerte esto puede ayudar a cualquiera que todavía tenga este problema en iOS8 + porque esta sigue siendo la pregunta principal que surge para este mensaje de error en particular.

Estaba usando PINRemoteImage para realizar una descarga sincronizada de una imagen a un UIImageView que estaba dentro de una UITableViewCell personalizada.

Para cambiar el tamaño de la fila correctamente (celdas dinámicas de altura usando el diseño automático) una vez que la imagen se cargó, llamé:

 self.tableView beginUpdates; self.tableView endUpdates; 

Luego recibí el mensaje “sin ruta de índice para la celda de tabla que se está reutilizando” y la aplicación se bloqueaba. Creía que el bloque PINRemoteImageManagerResult estaba en el hilo principal, pero resultó que no era así, por lo tanto, al asegurar que las actualizaciones de inicio / final se llamaron en el hilo principal se solucionó el problema.

 dispatch_async(dispatch_get_main_queue(), ^(void){ [self.tableView beginUpdates]; [self.tableView endUpdates]; }); 

Bueno, acabo de usar la mayor parte del día tratando de resolver esto, así que espero que esta explicación alternativa salve a alguien más en algún momento.

Tuve una tabla que daba este mensaje a veces , al cargar. Resultó ser causado por las notificaciones de KVO para los objetos de datos centrales que se activan mientras se carga la vista. (Al observar un cambio, mi controlador intentó llamar a reloadData en la tabla en cuestión. Se corrigió al no observar los objetos hasta que la vista había terminado de cargarse (anteriormente comencé a observar el objeto una vez que se asignó mediante el acceso)

TLDR: comprueba si puedes intentar volver a cargar tus datos de otra cosa que no sea el hilo principal.

Tal vez esto ayude a alguien: una vez tuve este error al actualizar una sola celda de vista de tabla. Tenía la intención de hacer algo como

 NSIndexPath *reloadRow = [NSIndexPath indexPathForRow:1 inSection:2]; [self._mainTableView reloadRowsAtIndexPaths:@[reloadWebViewRow] withRowAnimation:UITableViewRowAnimationFade]; 

Pero accidentalmente, escribí

 NSIndexPath *reloadRow = [NSIndexPath indexPathForItem:1 inSection:2]; 

Observe la diferencia de los dos indexpaths: uno se crea con indexPathForItem (incorrecto) y el otro con indexPathForRow (correcto). Todo esto dio como resultado un comportamiento muy extraño de tableView y el mensaje de error en el título.

Parece que mi problema se activó cuando intentaba actualizar la interfaz de usuario dentro de una parte del código que era una callback de una llamada web. Resolví forzar las actualizaciones de UI en el hilo principal. Usé código como este.

 void runOnMainQueueWithoutDeadlocking(void (^block)(void)){ if ([NSThread isMainThread]) { block(); } else { dispatch_sync(dispatch_get_main_queue(), block); } } 

Lo llamo de la siguiente manera dentro del bloque de éxito de mi llamada web de fondo.

 runOnMainQueueWithoutDeadlocking(^{ [self.tableView beginUpdates]; [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; }); 

Otra condición más …

Esto sucedió cuando, sin querer un encabezado, devolví nada.

Fijar:

 func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return "" }