CyberK CyberK - 3 months ago 16
iOS Question

NSFetchedResultsController not updating table

I've upgraded my app to Swift 2.0 and since then the NSFetchedResultsController doesn't behave correctly on iOS 8.4 (in iOS 9 it works as expected)

Scenario:
- A new entity is added
- Row appears in the tableview
- Property of the entity is changed so it shouldn't match the predicate of the fetchedtesultscontroller
- The row doesn't disappear from the tableview...

I can see the beginUpdates, the didChangeObject is called with the Delete type, and the endUpdates() is called.. My cache is nil.

Is this a known bug in xCode 7 with iOS 8.4? (the funny thing is that sometimes it DOES work, but most of the time it doesn't and it's crucial to my app...)

Thanks in advance!

p.s. I tried the if (indexPath != newIndexPath) stuff they say online, but the same result...

Answer

For anyone having the same issue, here is the solution:

In your:

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

Make sure the Update case is BEFORE the Insert case... so instead of this:

  func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
            switch type {
            case .Insert:
                self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Fade);
            case .Move:
                if(!indexPath!.isEqual(newIndexPath!)) {
                    self.tableView.moveRowAtIndexPath(indexPath!, toIndexPath: newIndexPath!);
                }
            case .Update:
                let cell = self.tableView.cellForRowAtIndexPath(indexPath!) as! UITableViewCell;
                self.configureCell(cell, atIndexPath: indexPath!);
                self.tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Fade);
            case .Delete:
                self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Fade)
            }
        }

you should have this:

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
        switch type {
        case .Update:
            let cell = self.tableView.cellForRowAtIndexPath(indexPath!) as! UITableViewCell;
            self.configureCell(cell, atIndexPath: indexPath!);
            self.tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Fade);
        case .Insert:
            self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Fade);
        case .Move:
            if(!indexPath!.isEqual(newIndexPath!)) {
                self.tableView.moveRowAtIndexPath(indexPath!, toIndexPath: newIndexPath!);
            }
        case .Delete:
            self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Fade)
        }
    }

It gave me a headache but finally found the solution...

Comments