2011-08-04 9 views
15

Tengo un UITableView bastante vainilla administrado por un NSFetchedResultsController para mostrar todas las instancias de una entidad de datos principal dada.tableView: cellForRowAtIndexPath llamado con nil indexPath después de eliminar el elemento

Cuando el usuario elimina una entrada en la vista de tabla al golpear sobre ella, tableView:cellForRowAtIndexPath: finalmente es llamado en mi UITableViewController con un nilindexPath. Dado que no esperaba que se llamara con un nilindexPath, la aplicación se bloquea.

Puedo solucionar el problema comprobando el valor nil y luego devolver una celda vacía. Esto parece funcionar, pero aún me preocupa que haya manejado algo mal. ¿Algunas ideas? ¿Alguien ha visto alguna vez tableView:cellForRowAtIndexPath: llamado con un nilindexPath?

Tenga en cuenta que esto solo ocurre cuando el usuario elimina de la vista de tabla deslizando sobre la celda. Al eliminar un elemento utilizando el modo de edición de vista de tabla, no sucede. ¿Cuál sería la diferencia entre las dos formas de eliminar una celda?

Entonces, ¿es realmente una situación correcta obtener nilindexPath en un método delegado de vista de tabla?

Mi código de controlador de vista es realmente estándar. Aquí es la supresión:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (editingStyle == UITableViewCellEditingStyleDelete) { 
     // Delete the row from the data source 
     NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath]; 
     [self.moc deleteObject:managedObject]; 
     NSError *error = NULL; 
     Boolean success = [self.moc save:&error]; 
     if (!success) { <snip> } 
     // actual row deletion from table view will be handle from Fetched Result Controller delegate 
     // [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
    } else { <snip> } 
} 

Esto conducirá al método NSFetchedResultsController delegado siendo llamados:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
    atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
    newIndexPath:(NSIndexPath *)newIndexPath 
{ 
    UITableView *tableView = self.tableView; 
    switch(type) { 

     case NSFetchedResultsChangeDelete: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

     case NSFetchedResultsChangeInsert: <snip> break; 
     case NSFetchedResultsChangeUpdate: <snip> break; 
     case NSFetchedResultsChangeMove: <snip> break; 
    } 
} 

Y, por supuesto, los métodos de fuente de datos son manejados por el NSFetchedResultsController, por ejemplo:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; 
    return [sectionInfo numberOfObjects]; 
} 

Muchas gracias.

+1

¿Ha verificado todos estos serán llamadas en el orden predicho? – Mundi

+1

Intenta llamar 'reloadData' en tu vista de tabla en' tableView: commitEditingStyle: forRowAtIndexPath' inmediatamente * después * de guardar los cambios en el contexto del objeto administrado. Tuve un problema similar con esto y volver a cargar la vista de tabla lo solucionó. – Greg

Respuesta

0

Me gustaría hacer esto, ya que está rellenando la tabla directamente desde su contexto administrado, ¿por qué no borrar primero eliminar el objeto del contexto administrado y luego actualizar inmediatamente la tabla desde el contexto usando reloadData. Pero la utilización de su enfoque, creo que es necesario agregar beginUpdates y endUpdates:

#pragma mark - 
#pragma mark Fetched results controller delegate 


- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
[self.tableView beginUpdates]; 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo 
     atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { 

switch(type) { 
    case NSFetchedResultsChangeInsert: 
     [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeDelete: 
     [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 
} 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
    atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
    newIndexPath:(NSIndexPath *)newIndexPath { 

UITableView *tableViews = self.tableView; 

switch(type) { 

    case NSFetchedResultsChangeInsert: 
     [tableViews insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeDelete: 
     [tableViews deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeUpdate: 
     [_delegate configureCell:[tableViews cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
     break; 

    case NSFetchedResultsChangeMove: 
     [tableViews deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     [tableViews insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade]; 
     break; 
} 
} 


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
    [self.tableView endUpdates]; 
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; 
    [self.tableView scrollToRowAtIndexPath:indexPath 
         atScrollPosition:UITableViewScrollPositionMiddle 
           animated:NO]; 
} 
2

Parece que va a eliminar la indexPath de mesa, pero la fuente de datos de tabla no se actualiza. ¿Ha verificado que el proceso de creación de la fuente de datos mediante NSFetchedResultsController está actualizando correctamente la fuente de datos de la tabla?

-1

Utilizo CoreData en vistas de tabla y les permito a los usuarios eliminar registros y actualizarlos todo el tiempo, los tengo en 4 aplicaciones sin encontrar el problema que mencionas.

He éstos Delegado Método FetchedResultsController en mi código

 - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates. 
    [self.myTableView beginUpdates]; 
} 


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates. 
     [self.myTableView endUpdates]; 

}

Cuestiones relacionadas