【问题标题】:Cocoa KVO:observeValueForKeyPath:ofObject:change:context: is called twice for one value changeCocoa KVO:observeValueForKeyPath:ofObject:change:context: 为一个值更改调用两次
【发布时间】:2013-06-24 03:20:35
【问题描述】:

我有一个 NSOperation 子类,它实现了 setFinished: 来生成 KVO 通知:

-(void)setFinished:(BOOL)isFinished
{
    LogError(@"%@ will will changing isFinished to %d",self,isFinished);
    [self willChangeValueForKey:@"isFinished"];
    LogError(@"%@ did will changing isFinished to %d",self,isFinished);
    _isFinished = isFinished;
    LogError(@"%@ will did changing isFinished to %d",self,isFinished);
    [self didChangeValueForKey:@"isFinished"];
    LogError(@"%@ did did changing isFinished to %d",self,isFinished);
}

我也确信我只将观察者添加到操作中一次。

奇怪的事情来了,有时候observeValueForKeyPath:ofObject:change:context:对于这个对象的isFinished键路径被调用了两次,参考日志,我发现setFinished:只调用了一次,而addObserver:forKeyPath:对于这个操作只调用了一次。

另外,我发现它的顺序是这样的:

will will changing isFinished to 1
did will changing isFinished to 1
will did changing isFinished to 1
calling observeValueForKeyPath for object
did did changing isFinished to 1
calling observeValueForKeyPath for object

请问有人知道吗?

【问题讨论】:

  • iphone 标签表示 iOS,而cocoa 表示 OSX。你是什​​么意思?
  • KVO 在两个系统上都是一样的。
  • @rmaddy 我只是想让我的问题多暴露一点,如果我确实遇到了一些规定,请通知我,谢谢。

标签: iphone objective-c cocoa key-value-observing


【解决方案1】:

如果你想负责调用willChangeValueForKey:didChangeValueForKey:,你必须告诉系统。您可以通过两种方式做到这一点:

  • 当键为finished 时,您可以在类上覆盖+automaticallyNotifiesObserversForKey:(类方法)以返回NO。这记录在“Manual Change Notification” in the *Key-Value Observing Programming Guide 下。

  • 您可以实现+automaticallyNotifiesObserversOfFinished 以返回NO。这记录在NSKeyValueObserving.h 头文件中,在+automaticallyNotifiesObserversForKey: 的评论中。

如果你没有正确实现这些类方法之一,系统会在setFinished:返回时自动通知观察者。看起来这就是您在日志中看到的内容。

【讨论】:

  • 支持来自 KVO 标头的注释:automaticallyNotifiesObserversOf<key> 变体已正确记录在 Leopard 的 Foundation Release Notes 中。
【解决方案2】:

你不需要实现'setFinished:'。

KVO 方法 observeValueForKeyPath:ofObject:change:context: 被 setFinished: 调用一次,因为您已经明确地使用

通知了更改

[self willChangeValueForKey:@"isFinished"];

解决方案是调用 [self willChangeValueForKey:@"isFinished"];仅当您按如下方式设置变量“完成”时:

[self willChangeValueForKey:@"isFinished"];
self.finished = YES;
[self didChangeValueForKey:@"isFinished"];

不覆盖 setFinished:

【讨论】:

  • 那里没有必要打电话给willChangeValueForKey:didChangeValueForKey:,因为self.finished = YES发送setFinished:消息,正如你所说,它会自动处理通知。
猜你喜欢
  • 2015-07-20
  • 2012-02-11
  • 1970-01-01
  • 2018-02-09
  • 2011-04-24
  • 1970-01-01
  • 1970-01-01
  • 2017-12-22
  • 2019-10-06
相关资源
最近更新 更多