2012-01-23 18 views
10

Durante el borrado Swype (la mayoría de las líneas importatnt de este método):Eliminar fila en vista de tabla con fetchedResultController

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
if (editingStyle == UITableViewCellEditingStyleDelete) 
    { 
    Table *deleteRow = [self.fetchedResultsController objectAtIndexPath:indexPath]; 
    [self.managedObjectContext deleteObject:deleteRow]; 
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
    } 
} 

Cuando fila borrar me sale este error:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 2.
The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

Si comento última línea de código ([tableView deleteRowsAtIndexPaths:...]) todo funciona bien (pero tengo que actualizar la vista para ver que se eliminó la fila).

¿Cómo hacerlo correctamente ..?

EDIT: Considerando responce @Kyr Dunenkoff he añadido:

- (void)controller:(NSFetchedResultsController*)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath*)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath*)newIndexPath 
{ 
    UITableView *tableV = [self tableView]; 
    switch(type) { 
     case NSFetchedResultsChangeDelete: 
      [tableV deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 

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

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

Sin embargo, esto no cambió el error estrellarse &. Atm acaba de causar que agregar nuevas filas ya no funcione.

Respuesta

14

Para hacer esto correctamente, implemente el método controller:didChangeObject:, dentro de él haga un switch para diferentes tipos de cambio, dentro del estuche NSFetchedResultsChangeDelete inserte su [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];. Porque cuando trabajas con fuentes de datos como NSFetchedResultsController, todos los cambios deben venir desde allí y tu tabla solo los refleja. Además, puede implementar controller:willChangeContent y controller:didChangeContent, poner [tableView beginUpdates] en willChange y [tableView endUpdates] en didChange.

+1

Por favor, verifique mi actualización superior, la corrección no está funcionando como lo implementé (¿puede estar equivocado ...?). ¡Gracias por responder! – Vive

+0

Hm. ¿Qué hay en su método [tableView: numberOfRowsInSection:]? Debería tener algo como 'return [[self.fetchedResultsController fetchedObjects] count];'. –

7

El problema es - como usted ha descubierto comentando hacia fuera - de su última línea:

[tableView deleteRowsAtIndexPaths:... 

La Tabla manzana Ver Guía de programación dice que tiene que hacer eso, pero en realidad no se supone a cuando se usa NSFetchedResultsController. La idea de NSFetchedResultsController es que es y se ocupa de actualizar la interfaz de usuario para mantenerla sincronizada con el modelo, de modo que no sea necesario. Por lo tanto, si simplemente elimina el objeto del modelo, el controlador de resultados obtenidos se encargará del resto.

[Actualizar] Vaya, no es del todo correcto lo que dije justo allí. El controlador de resultados obtenido no solo "se encargará del resto" sin ayuda. Es delegado se encargará del resto, pero alguien tiene que implementar su delegado. Tengo la costumbre de incluir la clase de ayuda CoreDataTablewViewController del curso Standford CS193p, que es simplemente una subclase UITableViewController que implementa todos los métodos recomendados en la documentación de NSFetchedResultsController. Lo que es más importante, implementa los métodos delegados que actualizan la vista de tabla cuando cambia el modelo.

Por lo que su enfoque actualizado sigue siendo correcta: Usted no debe poner los deleteRowsAtIndexPaths .. en el código que hace que el usuario eliminarlos, pero dejar que el controlador resultados descabellada unidad del proceso, e implementar el delegado para hacer realidad eso.

(conseguir la clase de ayuda aquí: http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2011-fall, y ver Clase 14 para ver cómo usarlo)

2

respuesta de Kyr es correcta, pero aquí es un ejemplo discreto de cómo eliminar una NSManagedObject de su base de datos, así a partir de la NSFetchedResultsController:

- (void) deleteObjectFromDBAndTable:(NSIndexPath *)indexPath forTable:(UITableView*)tableView 
{ 
    NSLog(@"Deleting object at row %d", indexPath.row); 

    // Delete the object from the data source 
    NSManagedObject *objToDelete = (NSManagedObject*)[self.fetchedResultsController objectAtIndexPath:indexPath]; 

    // Delete the object from the database 
    [DBHandler deleteObject:objToDelete andSave:YES]; 
} 

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

      [_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 

      break; 
     default: 
      break; 
    } 
} 
2

usted necesita asegurarse de que no se llama a sí mismo [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];. Al eliminar el objeto del contexto se disparará el NSFetchedResultsController para actualizarse a sí mismo Y a la tabla.

Cuestiones relacionadas