2010-10-30 21 views
8

Tengo una UITableView que muestra una lista de objetos almacenados con CoreData. Puedo eliminar un objeto usando el siguiente código:Animación de eliminación de fila en UITableView con CoreData da error de aserción

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 
if (editingStyle == UITableViewCellEditingStyleDelete) { 
    NSLog(@"Delete row"); 
    [managedObjectContext deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]]; 

    // Save the context. 
    NSError *error; 
    if (![managedObjectContext save:&error]) { 
     /*do this gracefully one day */ 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 
    [self refreshTables]; //where refreshTables just reloads the data the table is using and calls [self.tableView reloadData]; 
} 

} 

Pero no tiene animación ni estética.

Cuando intento para animar al reemplazar

[self refreshTables]; 

con

[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 

me sale el siguiente error:

Assertion failure in -[UITableView _endCellAnimationsWithContext:], >/SourceCache/UIKit_Sim/UIKit-1261.5/UITableView.m:920 2010-10-30 16:46:35.717 MyApp[38226:207] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted).'

He intentado tener los código en deleteRowsAtIndexPaths una variedad de lugares en el código commitEditingStyle sin lu ck (por ejemplo, antes de eliminar el objeto del mOC) pero parece que no puedo evitar este error.

Sé que el ejemplo de iPhoneCoreDataRecipes de Apple maneja el problema configurando un delegado para FetchedResultsController para manejar las filas de edición/eliminación, pero en esta etapa del desarrollo, si es posible, solo quiero una solución simple para animar esos objetos eliminados.

¿Cómo puedo animar la eliminación de una fila, antes/después de eliminar el objeto de mi managedObjectContext?

EDITAR: He intentado tener deleteRowsAtIndexPaths antes y después de eliminar el elemento del mOC, con el mismo error.

Respuesta

-2
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
     if (editingStyle == UITableViewCellEditingStyleDelete) { 
      NSLog(@"Delete row"); 

    // Delete the row first 
     [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 

    //Then delete the object. 
      [managedObjectContext deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]]; 

      // Save the context. 
      NSError *error; 
      if (![managedObjectContext save:&error]) { 
       /*do this gracefully one day */ 
       NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
       abort(); 
      } 
     } 


    } 
+0

No, eso no funciona. Lo intenté antes de publicar. Mismo error: Error de aserción en - [UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1261.5/UITableView.m:92 – glenstorey

0

¿Está utilizando un NSFetchedResultsController en absoluto?
Obtiene este error porque el objeto aún se encuentra en su fuente de datos de tabla vista.

Tal vez at this stage in development está utilizando el simple solution y rellene NSArrays con objetos de un NSFetchRequest. Entonces será inútil para eliminar el objeto del contexto de objeto gestionado


¿Está utilizando una caché para el NSFetchedResultsController? Acabo de tener otra mirada en la documentación y encontré esto:

A controller thus effectively has three modes of operation, determined by whether it has a delegate and whether the cache file name is set.

No tracking: the delegate is set to nil. The controller simply provides access to the data as it was when the fetch was executed.

Memory-only tracking: the delegate is non-nil and the file cache name is set to nil. The controller monitors objects in its result set and updates section and ordering information in response to relevant changes.

Full persistent tracking: the delegate and the file cache name are non-nil. The controller monitors objects in its result set and updates section and ordering information in response to relevant changes. The controller maintains a persistent cache of the results of its computation.

Así que el modo del controlador es "no seguimiento". Lo que significa que los objetos no se eliminan del controlador si se eliminan del objeto administrado.
¿Qué significa just reloads the data en el código de refreshTables? Intenta hacer lo mismo antes de eliminar las filas.
O agregue esas 20 líneas necesarias para que el delegado funcione.

+0

Estoy usando NSFetchedResultsController y una fuente de datos central sin problemas. El código sans-animation elimina con éxito el objeto coredata. Solo la animación está causando problemas. – glenstorey

+0

@glenstorey Supongo que no leí tu pregunta a fondo la primera vez, mira mi edición. –

17

Cuando usamos NSFetchedResultsController como DataSource de UITableView, no podemos invocar deleteRowsAtIndexPaths: withRowAnimation: en la función tableView: commitEditingStyle: forRowAtIndexPath:, que arrojará una excepción como pregunta mencionada.

Una forma de resolver este problema es mediante la invocación de [self.tableView reloadData] en controllerDidChangeContent: de protocolo NSFetchedResultsControllerDelegate. En realidad resuelve, sin embargo, ya no hay Delete Fade Animation.

Por lo tanto, la manera alternativa conveniente es invocando [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade] en controller: didChangeObject: atIndexPath: forChangeType: newIndexPath:.

Código de la muestra de la siguiente manera:


- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle 
    forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    // Delete NSManagedObject 
    NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath]; 
    [context deleteObject:object]; 

    // Save 
    NSError *error; 
    if ([context save:&error] == NO) { 
     // Handle Error. 
    } 
} 

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
     atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
     newIndexPath:(NSIndexPath *)newIndexPath 
{ 
    if (type == NSFetchedResultsChangeDelete) { 
     // Delete row from tableView. 
     [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
           withRowAnimation:UITableViewRowAnimationFade]; 
    } 
} 
+0

Esto funcionó para mí ... ¡excelente respuesta a un frustrante tipo de problema "a última hora de la tarde"! – seanicus

Cuestiones relacionadas