问题
I am trying to observe individual NSManagedObject
changes on NSManagedObjectContextWillSaveNotification
:
- (void)managedObjectContextWillSave:(NSNotification *)notification
{
for (NSManagedObject * object in self.mutableObservedManagedObjects)
{
if (object.hasChanges)
{
[self managedObjectWasUpdated:object];
}
}
}
The problem is that hasChanges
is true while object.changedValues
is empty, thus wrongly (?) triggering managedObjectWasUpdated:
.
I'm trying to understand why this is the case and if I should better check object.changedValues.count
before calling managedObjectWasUpdated:
.
isInserted
and isDeleted
are both false.
回答1:
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
}
回答2:
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.
回答3:
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.
回答4:
From iOS 7 you can also use hasPersistentChangedValues instead of changedValues. I think this performs better.
回答5:
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.
来源:https://stackoverflow.com/questions/26293852/nsmanagedobjects-haschanges-is-true-while-changedvalues-is-empty