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...
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...
It looks like iOS 8 bug and you can find more info here: https://forums.developer.apple.com/thread/11662#65178
If you want to fix it, try this code:
public func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case NSFetchedResultsChangeType(rawValue: 0)!:
break // iOS 8 bug - Do nothing if we get an invalid change type.
case .Insert:
// Insert here
break
case .Delete:
// Delete here
break
case .Move:
// Move here
break
case .Update:
// Update here
break
}
}
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