问题
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:
- You change some attributes -->
NSManagedObjectContextObjectsDidChangeNotification
is posted, and you can usechangedValuesForCurrentEvent
to see what changed. - Later, you save changes.
NSManagedObjectContextWillSaveNotification
is posted. You can callchangedValuesForCurrentEvent
, 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 (probablyNSDictionary
). Then whenNSManagedObjectContextWillSaveNotification
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