21

This is the code, I save the model via Magical Record:

MagicalRecord.saveWithBlock({ (localContext) -> Void in
                    var localNotification = CDNotification.MR_findFirstByAttribute("notificationID", withValue: notification.notificationID, inContext: localContext) as CDNotification
                    localNotification.readNumber = NSNumber(bool: true)
                })

Delete is called instead of update after the code above is called:

func controller(controller: NSFetchedResultsController, didChangeObject object: AnyObject, atIndexPath indexPath: NSIndexPath, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath) {
    switch type {
    case NSFetchedResultsChangeType.Insert:
        self.tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
    case NSFetchedResultsChangeType.Update:
        if let cell = self.tableView.cellForRowAtIndexPath(indexPath){
            self.configureCell(cell as TableViewCell, atIndexPath: indexPath, withNotification: object as CDNotification)
        }
        self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
    case NSFetchedResultsChangeType.Move:
        self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
        self.tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
    case NSFetchedResultsChangeType.Delete:
        self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
    default:
        return
    }
}

This only happens if I set the predicate for fetch request, in example:

fetchRequest.predicate = NSPredicate(format:"user == john")
Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
vburojevic
  • 1,666
  • 5
  • 24
  • 34
  • EXACTLY:-) The same problem. Did you find the answer? – Bartłomiej Semańczyk Sep 03 '15 at 15:00
  • Is there any workaround for this? This is a serious bug. I would check within `DELETE` case if it was really removed from database, but it was removed from `NSFetchedResultsController`, hence I do not know what object should I check if it exist in Core Data. Any ideas? – Bartłomiej Semańczyk Sep 03 '15 at 16:29
  • I have the same problem here: http://stackoverflow.com/questions/32377070/nsfetchedresultscontroller-remove-row-from-uitableview-after-update-relationship. But I update relationships instead of property. The same issue. – Bartłomiej Semańczyk Sep 03 '15 at 16:39
  • What iOS and Core Data version is this? – quellish Sep 03 '15 at 19:19
  • @quellish - `iOS9`, and what do you men by core data version? `Xcode7Beta6` in my case. But it dourest matter, because iOS8 and Xcode6 have the same issue. – Bartłomiej Semańczyk Sep 03 '15 at 21:31

2 Answers2

5

What is happening here is that instead of the NSFetchedResultsChangeUpdate change event you expect, you are getting a NSFetchedResultsChangeDelete followed by NSFetchedResultsChangeInsert. You may also see a NSFetchedResultsChangeMove with the same indexPath as source and destination. This is a known issue in several beta versions of iOS 9 22380191 and others.

quellish
  • 21,123
  • 4
  • 76
  • 83
3

I know, late answer, but maybe helpful. I had the same problem with iOS 11.3 and Xcode 9.3 and it was driving me mad. The solution was to provide the correct data type in the arguments array for the predicate. After changing it from string interpolation to the actual expected type (NSNumber in that particular case), the correct NSFetchedResultsChangeType was Update instead of Delete.

I chose string interpolation, because the data type (Bool in that particular case), was used as scalar type in the Core Data model and NSPredicate accepted the scalar type during compilation, but raised an runtime exception. Changing it to string interpolation fixed the runtime error and the predicate worked as expected, except the wrong NSFetchedResultsChangeType was called.

So it seems the bug in Core Data still exists or maybe this was intended to force the correct data type usage.

michael.zischka
  • 1,056
  • 7
  • 5
  • 1
    Worked for me changed NSPredicate(format: "isRemoved == %@", "NO") to NSPredicate(format: "isRemoved == NO") – Stany Miles May 08 '20 at 03:29
  • Does anyone have a radar for this. Apparently an Int64 and NSNumber interpolated to a NSExpression lead to different behaviors with the same queries... – TheCodingArt Jan 13 '21 at 03:23
  • @StanyMiles You are goddamn right. After changing NSPredicate(format: "%K = %@", "id", "\(id)") to NSPredicate(format: "id == \(id)"). It just worked!! Thanks you so much <3 – Thet Htun Sep 26 '21 at 17:24