iOS8 Swift: deleteRowsAtIndexPaths se bloquea

Estoy teniendo problemas para eliminar una fila de mi tablaView en Swift, iOS 8, Xcode 6 Beta 6. Cada vez que trato de eliminar una fila obtengo un error similar a las líneas de

Falla de aserción en – [UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3302.3.1/UITableView.m:1581 2014-08-30 20: 31: 00.971 Directorio de classs [13290: 3241692] *** Finalización de la aplicación debido a Excepción no detectada 'NSInternalInconsistencyException', motivo: 'Actualización no válida: número inválido de filas en la sección 1. La cantidad de filas contenidas en una sección existente después de la actualización (25) debe ser igual a la cantidad de filas contenidas en esa sección antes de la actualización (25), más o less el número de filas insertadas o eliminadas de esa sección (0 insertadas, 1 eliminadas) y más o less el número de filas movidas dentro o fuera de esa sección (0 movidas, 0 movidas).

He leído todas las respuestas a este problema frecuente, aquí, y siento que he cumplido las condiciones recomendadas. Parece que el elemento se elimina del model de datos: cuando vuelvo a cargar la aplicación, el elemento eliminado desaparece de la tabla, pero parece que hay algunos rests en el file sqlite apropiado y, por supuesto, las matemáticas no se sumn . El println que escupe el indexPath muestra la Sección y la Fila correctas. Estoy muy desconcertado Esto debería ser sencillo, pero me falta algo tonto, estoy seguro, sospecho en la eliminación del model de datos. Proyecto completo en Github .

func numberOfSectionsInTableView(tableView: UITableView!) -> Int { return fetchedResultController.sections.count } func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { return fetchedResultController.sections[section].numberOfObjects } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { let cell = tableViewMain.dequeueReusableCellWithIdentifier("CellMain", forIndexPath: indexPath) as UITableViewCell let personForRow = fetchedResultController.objectAtIndexPath(indexPath) as Person cell.textLabel.text = personForRow.fullName() return cell } func tableView(tableView: UITableView!, canEditRowAtIndexPath indexPath: NSIndexPath!) -> Bool { return true } func tableView(tableView: UITableView!, editingStyleForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCellEditingStyle { return UITableViewCellEditingStyle.Delete } func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) { println("section and row \(indexPath.section) \(indexPath.row) ") if (editingStyle == UITableViewCellEditingStyle.Delete) { let personForRow : NSManagedObject = fetchedResultController.objectAtIndexPath(indexPath) as Person context?.deleteObject(personForRow) context?.save(nil) tableViewMain.beginUpdates() tableViewMain.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade) tableViewMain.endUpdates() } 

Es fácil reproducir su crash con un proyecto de plantilla de detalle maestro de datos de Xcode Core. Como regla general, cuando utiliza NSFetchedResultsController , realmente debería usar NSFetchedResultsControllerDelegate (lo ha declarado pero no lo usa).

Elimine esas líneas en su tableView:commitEditingStyle:forRowAtIndexPath: method:

 tableViewMain.beginUpdates() tableViewMain!.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Fade) tableViewMain.endUpdates() 

Y agregue esas líneas a su class viewController:

 func controllerWillChangeContent(controller: NSFetchedResultsController) { tableViewMain.beginUpdates() } func controller(controller: NSFetchedResultsController!, didChangeSection sectionInfo: NSFetchedResultsSectionInfo!, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { switch type { case .Insert: tableViewMain.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade) case .Delete: tableViewMain.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade) default: return } } func controller(controller: NSFetchedResultsController!, didChangeObject anObject: AnyObject!, atIndexPath indexPath: NSIndexPath!, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath!) { switch type { case .Insert: tableViewMain.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade) case .Delete: tableViewMain.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) case .Update: return //Should also manage this case!!! //self.configureCell(tableView.cellForRowAtIndexPath(indexPath), atIndexPath: indexPath) case .Move: tableViewMain.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) tableViewMain.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade) default: return } } func controllerDidChangeContent(controller: NSFetchedResultsController!) { tableViewMain.endUpdates() } 

Esto debería arreglar tu problema.

Creo que esto es simplemente un problema de almacenamiento en caching. Su fetchedResultController no fetchedResultController a generar automáticamente sus resultados, ya que almacena en caching sus resultados. Eso significa que cuando tableView:numberOfRowsInSection: se vuelve a llamar, el recuento de resultados aún retorna 25 aunque eliminó un elemento.