Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Identifying old and new values on changed objects with NSManagedObjectContextWillSaveNotification

I am trying to track changes to objects in a core data context, tracking the name of properties that have changed along with the old and new values.

I've registered for NSManagedObjectContextWillSaveNotification to receive a notification when a save is about to occur, and can pull out the inserted/updated/deleted objects from the context... I can then see the changed values using .changedValues.

However, I am having difficulties retrieving the old values...

As an example, I have an object that tracks a position, and so one of the changes comes back with:

po [obj changedValues]
{
    originX = 260;
    originY = 180;
}

This gives me the new values for the properties that have changed on the object. To try and get the old values, I'm then using changedValuesForCurrentEvent, which according to the docs should return

"a dictionary containing the keys and old values of persistent properties that have changed since the last posting of NSManagedObjectContextObjectsDidChangeNotification"

However, when I try this, it is coming back empty...:

po [obj changedValuesForCurrentEvent]
{
}

How can I capture the old and new values?

like image 236
John Martin Avatar asked Feb 13 '23 01:02

John Martin


2 Answers

You're mixing up your notifications. NSManagedObjectContextObjectsDidChangeNotification gets called any time you change values on a managed object, even though you haven't saved changes yet. NSManagedObjectContextWillSaveNotification gets called later on when you save. So the sequence is:

  1. You change some attributes --> NSManagedObjectContextObjectsDidChangeNotification is posted, and you can use changedValuesForCurrentEvent to see what changed.
  2. Later, you save changes. NSManagedObjectContextWillSaveNotification is posted. You can call changedValuesForCurrentEvent, but it's not helpful because it returns changes since the last did-change notification. There are no changes since the last did-change notification. If there were, you would have received another one. That method is documented to be useful on a did-change notification, not on a will-save notification.

If you want the old values and you want to get them when the will-save notification is posted, you have a couple of options:

  • Listen for NSManagedObjectContextObjectsDidChangeNotification. Cache information about changes in some collection object (probably NSDictionary). Then when NSManagedObjectContextWillSaveNotification happens, look up those changes, process them, and clear the change cache. OR...
  • When you get NSManagedObjectContextWillSaveNotification, create a second local managed object context. Since this is a will save notification, you can still fetch the old values. So, fetch each object that's getting saved and compare the before and after values to see what's different.
like image 77
Tom Harrington Avatar answered Feb 16 '23 03:02

Tom Harrington


Although this question is 4 years old, Eddie's answer was very helpful. I made a little change to his answer. All the credits goes to him.

object.setValuesForKeys(object.committedValues(forKeys: object.changedValues().map { $0.key }))
like image 36
ahagbani Avatar answered Feb 16 '23 02:02

ahagbani