I am trying to observe individual NSManagedObject
changes on NSManagedObjectContextWillSaveNotification
:
- (void)managedObjectContextWi
In my experience, if the entity already existed, you loaded it and then you set a value to a property that is equal to its previous value, then the record will be marked as updated, hasChanges
will return YES
, and changedValues
will be empty. When you save the context, what gets updated is a special Core Data column called Z_OPT, which refers to the number of times an entity has been updated. For these situations you can do something like this before saving:
for (NSManagedObject *managedObject in context.updatedObjects.objectEnumerator) {
if (!managedObject.changedValues.count) {
[context refreshObject:managedObject mergeChanges:NO];
}
}
in order to don't even update the Z_OPT value.
From iOS 7 you can also use hasPersistentChangedValues instead of changedValues. I think this performs better.
Do you have any transient attributes on your entity? I am seeing the behavior you describe, and I've written some test code that shows that modifying a transient attribute causes hasChanges
to return true
, while changedValues
is empty.
You can avoid this behavior by using setPrimitiveValue:forKey:
to modify your transient attribute or the equivalent method generated by Core Data (setPrimitiveFoo:
for an attribute named foo
). You could also implement the transient attribute's setter to do this for you.
I encountered the same issue. Instead of getting the flags, I just checked if changedValues() is empty.
For Swift:
if !managedObject.changedValues().isEmpty {
// Has some changed values
}
According to doc, hasChanges
will return YES if the receiver has been inserted, has been deleted, or has unsaved changes, otherwise NO.
In your case, you can check isInserted
, isUpdated
, isDeleted
flag to find what happened to your managed object. changedValues
only show the properties that have been changed since last fetching or saving the receiver.