This is an error:
CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. attempt to delete and reload the same index path ( {length = 2, path = 0 - 0}) with userInfo (null)
This is my typical NSFetchedResultsControllerDelegate
:
func controllerWillChangeContent(controller: NSFetchedResultsController) { tableView.beginUpdates() } func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { let indexSet = NSIndexSet(index: sectionIndex) switch type { case .Insert: tableView.insertSections(indexSet, withRowAnimation: .Fade) case .Delete: tableView.deleteSections(indexSet, withRowAnimation: .Fade) case .Update: fallthrough case .Move: tableView.reloadSections(indexSet, withRowAnimation: .Fade) } } func controller(controller: NSFetchedResultsController, didChangeObject anObject: NSManagedObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { switch type { case .Insert: if let newIndexPath = newIndexPath { tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade) } case .Delete: if let indexPath = indexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) } case .Update: if let indexPath = indexPath { tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None) } case .Move: if let indexPath = indexPath { if let newIndexPath = newIndexPath { tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade) } } } } func controllerDidChangeContent(controller: NSFetchedResultsController) { tableView.endUpdates() }
in viewDidLoad()
:
private func setupOnceFetchedResultsController() { if fetchedResultsController == nil { let context = NSManagedObjectContext.MR_defaultContext() let fetchReguest = NSFetchRequest(entityName: "DBOrder") let dateDescriptor = NSSortDescriptor(key: "date", ascending: false) fetchReguest.predicate = NSPredicate(format: "user.identifier = %@", DBAppSettings.currentUser!.identifier ) fetchReguest.sortDescriptors = [dateDescriptor] fetchReguest.fetchLimit = 10 fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchReguest, managedObjectContext: context, sectionNameKeyPath: "identifier", cacheName: nil) fetchedResultsController.delegate = self try! fetchedResultsController.performFetch() } }
This seems to be a bug in iOS 9 (which is still beta) and is also discussed in the Apple Developer Forum
I can confirm the problem with the iOS 9 Simulator from Xcode 7 beta 3. I observed that for an updated managed object, the didChangeObject:
delegate method is called twice: Once with the NSFetchedResultsChangeUpdate
event and then again with the NSFetchedResultsChangeMove
event (and indexPath == newIndexPath
).
Adding an explicit check for indexPath != newIndexPath
as suggested in the above thread seems to solve the problem:
case .Move: if indexPath != newIndexPath { tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With