NSManagedObject的hasChanges为true,而changedValues为空

26

我正在尝试在NSManagedObjectContextWillSaveNotification上观察单个NSManagedObject的更改:

我想要观察每个NSManagedObject的变化,这是通过使用NSManagedObjectContextWillSaveNotification实现的:

- (void)managedObjectContextWillSave:(NSNotification *)notification
{
    for (NSManagedObject * object in self.mutableObservedManagedObjects)
    {
        if (object.hasChanges)
        {
            [self managedObjectWasUpdated:object];
        }
    }
}
问题在于object.changedValues为空,但是hasChanges为true,因此错误地(?)触发了managedObjectWasUpdated:

我正在尝试了解这种情况的原因,以及在调用managedObjectWasUpdated:之前是否应该更好地检查object.changedValues.count


isInsertedisDeleted都为false。

6个回答

13

根据我的经验,如果实体已经存在,您加载它,然后将一个属性的值设置为与其之前的值相等,则记录将被标记为已更新,hasChanges将返回YES,而changedValues将为空。当您保存上下文时,会更新一个名为Z_OPT的特殊Core Data列,该列指的是实体已更新的次数。对于这些情况,在保存之前可以执行以下操作:

for (NSManagedObject *managedObject in context.updatedObjects.objectEnumerator) {
    if (!managedObject.changedValues.count) {
        [context refreshObject:managedObject mergeChanges:NO];
    }
}
为了不更新Z_OPT值。

2
我相信这是最准确的答案。hasChanges 基于 Core Data 知道的所有内容(包括 Z_OPT)。changedValues() 报告实体中不同的字段。在大多数情况下,应用程序可能更关心 changedValues().isEmpty - Colin M
2
你可以使用在 NSManagedObject 中引入的新属性 var hasPersistentChangedValues: Bool,而不是检查 changedValues.count - Wojciech Nagrodzki
1
很遗憾,[NSManagedObjectContext -hasChanges] 仍然会是 true - ReDetection
显然,改变瞬态值也会将对象标记为已更新,但没有更改的值。 - Frizlab

8
我遇到了相同的问题。我没有获取标志,而是检查了changedValues()是否为空。
对于Swift:
if !managedObject.changedValues().isEmpty {
    // Has some changed values
}

这个可以用,但是这并不是被记录下来的行为,让人想知道苹果什么时候会破坏它... :( - Jan Nash

8

iOS 7以后,您还可以使用hasPersistentChangedValues而不是changedValues。我认为这样表现更好。


3
确实,hasPersistentChangedValues 是最佳选择。根据头文件的注释,如果任何持久化属性与其上次保存状态不相等,则 hasPersistentChangedValues 返回 YES。 与现有的 -hasChanges 方法不同,它只是一个简单的脏标志,并且包括瞬态属性,而关系故障不会被不必要地触发。 - Jonny

3

根据文档,如果接收者已插入、已删除或有未保存的更改,hasChanges 将返回 YES,否则为 NO。

在您的情况下,您可以检查 isInsertedisUpdatedisDeleted 标志以查找您的托管对象发生了什么。 changedValues 仅显示自上次获取或保存接收器以来已更改的属性。


4
我遵循了文档,isInsertedisDeleted都是false,isUpdated为true,但没有changedValues。 (注:该句话缺少上下文,因此可能存在歧义或误译,请根据上下文综合判断。) - Rivera

0

当与NSManagedObject相关的另一个托管对象发生更改时,根据我的观察,NSManagedObject有时会有trueisUpdated,但不总是,而changedValues为空。

在其他情况下,isUpdatedfalse,并且再次changedValues为空。

这里changedValues为空似乎是正确的行为。我不清楚isUpdated为什么会有变化的原因。在我的生产代码中观察到这一点后,我正在使用希望能够重现此问题的简单示例项目来撰写错误报告提交给Apple。

为了解决我的功能问题,在我这种情况下,我修改了我的代码,以便在这些关系中的对象发生更改时自动设置父对象上的timestampModified,以确保isUpdated始终一致地设置为true


0

你的实体上有任何瞬态属性吗?我看到了你描述的行为,并编写了一些测试代码,显示修改瞬态属性会导致hasChanges返回true,而changedValues为空。

您可以通过使用setPrimitiveValue:forKey:来修改您的瞬态属性或由Core Data生成的等效方法(对于名为foo的属性,使用setPrimitiveFoo:)。您还可以实现瞬态属性的setter来自动完成此操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接