Identifying old and new values on changed objects with NSManagedObjectContextWillSaveNotification

两盒软妹~` 提交于 2020-02-02 04:41:26

问题


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?


回答1:


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.



回答2:


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 }))



回答3:


I know this question is old, but there is a better way than the accepted answer. You can access the previous values via committedValues(forKeys:) in combination with changedValues(). There is no need to handle NSManagedObjectContextObjectsDidChangeNotification or to create another managed object context.

Here is some sample code that I use:

// For some reason, the Swift compiler chokes on the type of object.changedValues().keys.
// It should be of type [String], but it complains that it is of type `Dictionary<String, Any>.Keys`
// which is useless. Ah, the joys of Apple programming...
// Work around that like so:
var changedKeys = [String]()
for (key, _) in object.changedValues() {
    changedKeys.append(key)
}
let oldData = object.committedValues(forKeys: changedKeys)



回答4:


Sounds like you should call "changedValuesForCurrentEvent" only when you receive your "NSManagedObjectContextWillSaveNotification" notification.

And if "changedValuesForCurrentEvent" still returns a null dictionary or object, check to see if the notification had anything useful in it's "userInfo" dictionary itself. It also may be that there has not been a NSManagedObjectContextObjectsDidChangeNotification" posted, like you posted from the docs up there.



来源:https://stackoverflow.com/questions/23433838/identifying-old-and-new-values-on-changed-objects-with-nsmanagedobjectcontextwil

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!