【问题标题】:Why is KVO sending a change notification when both the new and old values are the same?当新旧值都相同时,为什么 KVO 会发送更改通知?
【发布时间】:2013-07-16 18:45:04
【问题描述】:

我有一个实体,它是 NSManagedObject 的子类,称为 Event。我还为 KVO 更改通知注册了该实体的一些建模属性:

[self.event addObserver:self
             forKeyPath:@"numGuests"
                options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                context:&numGuestsContext];

[self.event addObserver:self
             forKeyPath:@"checkedIn"
                options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                context:&checkedInContext];

[self.event addObserver:self
             forKeyPath:@"seatedCount"
                options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                context:&seatedContext];

然而,即使更改字典中的 NSKeyValueChangeOldKey 和 NSKeyValueChangeNewKey 的值相等,observeValueForKeyPath 方法通知似乎也会被触发???

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
    NSNumber *oldValue = [change valueForKey:NSKeyValueChangeOldKey];
    NSNumber *newValue = [change valueForKey:NSKeyValueChangeNewKey];

    if ([oldValue isEqualToNumber:newValue])
    {
        return;
    }

现在我只需要进行快速的健全性检查,看看它们是否相等,但我想了解为什么这个通知一开始就会被触发?

更新:@jszumski 在 cmets 中提到这很可能是因为对象不同但逻辑上相等。事件实体对象始终具有相同的地址,但是我正在观察的对象(实体中的一个属性)不断更改地址,尽管我不确定为什么?

我想知道在 bg 查询线程中访问这个值是否会导致 Core Data 在实体中创建具有相同值的新内部对象?

【问题讨论】:

  • oldValuenewValue 是逻辑上相等的不同对象吗?
  • 我不明白?该方法被触发是因为您更新了 NSManagedObject 子类中的某些属性(您正在观察)。无论新旧值是否相同,它都会被触发。
  • @jszumski 看起来可能是这种情况。事件实体对象始终具有相同的地址,但是我正在观察的对象(实体中的一个属性)不断更改地址,尽管我不确定为什么? Core Data 是否会在获取时在实体内创建新对象?
  • 这个“问题”得到了我预期的“答案” SWEEETTT!!!

标签: ios core-data key-value-observing


【解决方案1】:

简单地说,您假设了NSKeyValueObservingOptions 的功能。它们不像您期望的那样工作。您发送的标志仅决定更改字典的内容是什么。每当调用 setter 时,观察者总是被触发。

此外,当您发送标志 oldnew 时,实际上只是说“我想要旧值和新值。我不在乎它们是否相等”。

请阅读参考资料以了解更多信息:

NSKeyValueObservingOptions

这些常量被传递给 addObserver:forKeyPath:options:context: 并确定作为更改的一部分返回的值 字典传递给 观察ValueForKeyPath:ofObject:change:context:。如果你可以通过 0 不需要更改字典值。

【讨论】:

  • 嗨,我了解标志在做什么。我将它们包括在内是为了说明旧与新的价值是相同的。我的印象是观察者只有在值改变时才会被触发。正如我在更新中提到的,我认为问题与对象地址不同但其值相同有关。
  • @s.newave 这就是我用粗体指出的,对吧?观察者总是被触发。调用 setter 或 will/didChangeValueForKeypath:。不考虑它们是否相等。你应该自己做检查。
  • Mazyod 关于默认行为是正确的——它总是通知。如果您想实现一个仅在值实际更改时通知的对象,则必须覆盖 +automaticallyNotifiesObserversForKey: 以针对有问题的键返回 NO,然后您必须为看起来的每个键实现设置器为了平等,然后仅在值实际上不同时才调用-will/didChangeValueForKey:。如果你无法控制被观察对象的实现,你可以子类化,但一般来说,你运气不好。
  • @Mazyod 我认为这行不通。 willChangeValueForKey: 怎么会知道这个值是否即将改变?
  • @Mazyod: -will/didChangeValueForKey: 无权访问更改字典。
猜你喜欢
  • 2013-01-30
  • 1970-01-01
  • 1970-01-01
  • 2019-07-25
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
  • 2023-02-11
  • 2012-09-06
相关资源
最近更新 更多