【问题标题】:How should I unregister for KVO on self?我应该如何自行注销 KVO?
【发布时间】:2011-02-02 06:27:10
【问题描述】:

我正在尝试使用 KVO 观察 UIView 子类的属性,以便通过调用 drawRect: 来触发绘图。在我的initWithFrame: 中,我有这个:

...
self.observedKeysThatTriggerRedraw = [NSArray arrayWithObjects:@"name", nil];
for (NSString *aKey in self.observedKeysThatTriggerRedraw) {
    [self observeValueForKeyPath:aKey ofObject:self change:nil context:redrawContextString];
}
...

redrawContextString 是这个类独有的常量NSString

KVO 通知按应有的方式触发,这会正确触发重绘。问题是注销 KVO。如果我不取消注册,一切都会正常运行,但如果我将其放在 dealloc 的顶部,则会出现异常:

for (NSString *aKey in self.observedKeysThatTriggerRedraw) {
    [self removeObserver:self forKeyPath:aKey];
}

self.name = nil;
...
[super dealloc];

我在控制台中收到此消息,当它到达 removeObserver:forKeyPath: 时发生崩溃:

CoreAnimation:忽略异常:无法从 中删除键路径“名称”的观察者 ,因为它没有注册为观察者

当您观察self 时,是否有一些技巧可以取消注册 KVO?我的观察员是否在dealloc 被调用时为我取消注册?我在很多地方读到过你不应该在 dealloc 中取消注册 KVO,但我不确定在观察 self 时我还能在哪里做。

【问题讨论】:

  • 您绝对应该避免在 init、dealloc 和其他部分构造/破坏的状态下发送消息。
  • 我认为这有点像说“goto 是邪恶的”。您还建议如何自行取消注册 KVO?如果不使用self.property = nil;,您将如何在 dealloc 中释放自动合成的保留属性?
  • @Justin,在init 中,在self=[super init] 之后向自己发送消息是完全安全的。在dealloc 中,您在发送[super dealloc] 之前向自己发送消息是绝对安全的。值得注意的例外是 NSManagedObject。
  • @Nick Forge 的陈述并不等同。 goto 产生定义明确的行为。
  • 真正的问题是发送具有副作用的消息,这些副作用会导致部分构造/解构状态出现问题。例如出于非常明显的原因,应该避免在 init/dealloc 中调用属性设置器非标准的属性访问器,尤其是在它调用其他属性/ivars 的情况下(除非你真的很小心)。问题实际上不仅仅是向自己发送消息,一旦你调用 self = [super init],这是 100% 安全的。

标签: iphone key-value-observing


【解决方案1】:

您实际上还没有将视图注册为addObserver:forKeypath:options:context: 的观察者。您应该将自己注册为观察者,或者(如果您不以标准方式使用 KVO,请手动发送 observeValueForKeyPath...),您不应该尝试将自己取消注册为观察者。

【讨论】:

  • 哈哈,在我重写代码的过程中,我确实把observeValueForKeyPath:... 放在了addObserver:forKeyPath:... 应该放在的位置。出于某种原因,observeValueFor… 直觉上似乎是开始观察某事的合理方法名称。
猜你喜欢
  • 1970-01-01
  • 2011-10-29
  • 2023-04-08
  • 1970-01-01
  • 2014-03-31
  • 2015-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多