【发布时间】: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