Célula personalizada en la tabla vacía con NSFetchedResultsController

Estoy intentando colocar una celda vacía personalizada cuando mi UITableView está vacío.

Yo uso el siguiente código:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { int count = [self.fetchedResultsController fetchedObjects].count; if (count == 0) { return 1; } return count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell * cell = nil; int count = [self.fetchedResultsController fetchedObjects].count; if (count == 0) { // return empty cell cell = [self getEmptyCellOfTableView:tableView cellForRowAtIndexPath:indexPath]; } else { cell = [self getMyQuestionCellOfTableView:tableView cellForRowAtIndexPath:indexPath]; } return cell; } 

Implementación de FRC didChangeObject :

 - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext) { switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeMove: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; } } } 

Esto funciona perfectamente, el problam es cuando fetchedObject.count> 0 que obtengo el siguiente error:

 CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to - controllerDidChangeContent: Invalid update: invalid number of rows in section 0. 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 (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null) 

Entiendo que esto sucede porque inserté 1 nueva fila y el conteo se queda en 1 en vez de convertirse en 2.

¿Cómo puedo solucionarlo para que se ajuste a mi comportamiento?

Después de una actualización de vista de tabla, el valor devuelto por numberOfRowsInSection debe coincidir exactamente con el número anterior de filas más el número de filas insertadas less el número de filas eliminadas.

En su caso, cuando se inserta el primer object, se insertRowsAtIndexPaths en el método de delegado de FRC para el nuevo object, pero en lugar de mostrar una fila adicional, la celda "vacía" se reemplaza por una celda diferente, por lo que el número de filas es aún una

Debería funcionar si modifica el controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: método de delegado de FRC controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: siguiente manera:

 case NSFetchedResultsChangeInsert: if ([[self.fetchedResultsController fetchedObjects] count] == 1) { // First object inserted, "empty cell" is replaced by "object cell" [tableView reloadRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; } else { [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; } break; case NSFetchedResultsChangeDelete: if ([[self.fetchedResultsController fetchedObjects] count] == 0) { // Last object removed, "object cell" is replaced by "empty cell" [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else { [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } break; 

PSA: Si aún no ha revisado la solución de Yang Meyer para mostrar una celda en una table vacía, le sugiero que lo haga. Es una forma inteligente y mucho más sencilla de manejar una tabla vacía o NSFetchedResultsController vacío.

Mejores prácticas de Yang Meyer para manejar vistas vacías de la table

La forma en que lo usé era, en mi viewDidLoad , viewDidLoad , inicialmente supondría que los resultados estaban vacíos. Solo cuando mi fetchedResultsController tenía objects, ¿cambio de nuevo la fuente de datos?

FJFetchedDataController.h

 @interface FJFetchedDataTableController : UITableViewController <NSFetchedResultsControllerDelegate, UITableViewDelegate> @end 

FJFetchedDataController.m

 @implementation FJFetchedDataTableController { @private FJEmptyDataSource *_emptyDataSource; }; - (void)viewDidLoad { [super viewDidLoad]; // create the empty data source _emptyDataSource = [[FJEmptyDataSource alloc] init]; // point the tableView to the empty data source self.tableView.dataSource = _emptyDataSource; self.fetchedResultsController.delegate = self; // TODO: configure your fetchedResultsController here NSError *error; if (![self.fetchedResultsController performFetch:&error]) { // TODO: error handling } if ([self.fetchedResultsController.fetchedObjects count]) { // set the table source back to itself (or whatever you want as the data source) // since we know we have results self.tableView.dataSource = self; return; } } 

Simple, pero realmente efectivo.