¿Cómo usar newIndexPath para NSFetchedResultsChangeUpdate?

Creí que lo conseguí . Pero un nuevo locking que encontré en mi aplicación dice lo contrario. Entonces, cualquiera sabe el código realmente correcto para NSFetchedResultsChangeUpdate cuando newIndexPath es no-nil y no es lo mismo que indexPath en -controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: 😕

Acabo de ver una falla en la actualización, y parece que el newIndexPath se proporciona como una ruta de índice en los objects de control de resultados obtenidos cuando esa ruta de índice no coincide con la ruta de índice necesaria para recuperar la celda de la tabla. Considera lo siguiente:

  1. Una vista de tabla tiene una sección en el índice 0 con 15 ítems.
  2. Se elimina el elemento en el índice 13 (el penúltimo elemento)
  3. El artículo en el índice 14 (el último artículo) se actualiza

En el caso anterior, suponiendo que está utilizando [tableView beginUpdates] y [tableView endUpdates] en el controllerWill/DidChangeContent: apropiado controllerWill/DidChangeContent: methods, necesitará usar el parámetro indexPath para recuperar la celda de la tabla para actualizar (que será la sección 0, índice 14) y el parámetro newIndexPath para recuperar el object para configurar la celda con el controller de resultados (que será la sección 0, índice 13).

Supongo que funciona de esta manera porque la eliminación parece haber sucedido en lo que respecta al controller de resultados, pero no ha sucedido en la vista de tabla (debido a las llamadas beginUpdates/endUpdates envolviendo las actualizaciones). Tiene sentido si considera el caso anterior, pero parece que toda la documentation no considera este caso.

Entonces, la respuesta a la pregunta es que parece que debe usar el parámetro indexPath para recuperar una celda de la vista de tabla y el parámetro newIndexPath para recuperar el object del controller de resultados extraído. Tenga en count que si no ha habido una inserción o eliminación parece que pasa nil para newIndexPath , por lo que en este caso tendría que usar indexPath para ambos propósitos.

Si un object de NSFetchedResultsController cambia y se mueve al "mismo time" -controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: envía el tipo NSFetchedResultsChangeUpdate ( ver aquí ).

Mi solución es cambiar el tipo para mover cada vez que el tipo se actualiza y indexPath no es igual a newIndexPath

 - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { UITableView *tableView; if (controller == self.fetchedResultsController) { tableView = self.tableView; } else { tableView = self.searchDisplayController.searchResultsTableView; } // type is "update" ---> should be "move" if (type == NSFetchedResultsChangeUpdate && [indexPath compare:newIndexPath] != NSOrdenetworkingSame && newIndexPath != nil) { type = NSFetchedResultsChangeMove; } switch(type) { case NSFetchedResultsChangeInsert: [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self fetchedResultsController:controller configureCell:(UITableViewCell*)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; break; case NSFetchedResultsChangeMove: [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft]; [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationRight]; break; } } 

Luego tiene que actualizar la vista de tabla

 - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { [self.tableView endUpdates]; [self.tableView reloadData]; } 

¡Espero que esto sea útil!