Search code examples
iosswiftcore-datansfetchedresultscontroller

Why is NSFetchedResultsControllerDelegate 'changeObject' being called


I'm using some boilerplate code that implements the NSFetchedResultsControllerDelegate in a UITableView. When I perform a segue away from the table view, this delegate method gets called:

    func controller(controller: NSFetchedResultsController,
                didChangeObject anObject: AnyObject,
                atIndexPath indexPath: NSIndexPath?,
                forChangeType type: NSFetchedResultsChangeType,
                newIndexPath: NSIndexPath?) {

    guard let newIndexPath = newIndexPath else{
        fatalError("No indexPath received") // Gets to this line, thus causing a crash
    }
    switch(type){

    case .Insert:
        tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)

    case .Delete:
        tableView.deleteRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)

    case .Update:
        tableView.reloadRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)

    case .Move:
        tableView.deleteRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
        tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
    }

}

It keeps crashing because a nil value is being passed in for the parameter 'newIndexPath'. I'm able to bypass this by setting my fetchedResultsController variable (the variable responsible for calling the delegate methods) to nil when I call prepareForSegue.

Why does this method get called on a segue? And how can I pass in the correct newIndexPath? Should I even worry about this? It doesn't seem like setting the variable responsible for calling this delegate method to nil is a very graceful way to take care of this problem.


Solution

  • It happens when your FRC delegate receives .Delete change:

    newIndexPath The destination path for the object for insertions or moves (this value is nil for a deletion).

    https://developer.apple.com/library/ios/documentation/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/#//apple_ref/occ/intfm/NSFetchedResultsControllerDelegate/controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:

    You should use indexPath with .Delete, .Update and with tableView.deleteRowsAtIndexPaths in .Move section.

    Use newIndexPath for .Insert and tableView.insertRowsAtIndexPaths in .Move section.