ios KVO - 如何检查对象是否是观察者?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9231896/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
KVO - How to check if an object is an observer?
提问by Josh Buhler
When observing a value on an object using addObserver:forKeyPath:options:context:
, eventually you'll want to call removeObserver:forKeyPath:
on that object to clean up later. Before doing that though, is it possible to check if an object actually is observing that property?
当使用 观察对象上的值时addObserver:forKeyPath:options:context:
,最终您将希望调用removeObserver:forKeyPath:
该对象以稍后进行清理。不过,在这样做之前,是否可以检查一个对象是否确实在观察该属性?
I've tried to ensure in my code that an object is only having an observer removed when it needs to be, but there are some cases where it's possible that the observer may try to remove itself twice. I'm working to prevent this, but just in case, I've just been trying to figure out if there's a way to check first if my code actually is an observer of something.
我试图在我的代码中确保一个对象只在需要时移除观察者,但在某些情况下,观察者可能会尝试两次移除自身。我正在努力防止这种情况发生,但以防万一,我只是想弄清楚是否有办法首先检查我的代码是否确实是某个事物的观察者。
回答by Nikolai Ruhe
[...] is it possible to check if an object actually is observing that property?
[...] 是否可以检查对象是否确实在观察该属性?
No. When dealing with KVO you should always have the following model in mind:
不。在处理 KVO 时,您应该始终牢记以下模型:
When establishing an observation you are responsible for removing that exact observation. An observation is identified by its context—therefore, the context has to be unique. When receiving notifications (and, in Lion, when removing the observer) you should always test for the context, not the path.
在建立观察时,您有责任删除该确切观察。观察由其上下文标识——因此,上下文必须是唯一的。接收通知时(以及在 Lion 中移除观察者时),您应该始终测试上下文,而不是路径。
The best practice for handling observed objects is, to remove and establish the observation in the setter of the observed object:
处理观察对象的最佳实践是,在观察对象的 setter 中删除和建立观察:
static int fooObservanceContext;
- (void)setFoo:(Foo *)foo
{
[_foo removeObserver:self forKeyPath:@"bar" context:&fooObservanceContext];
_foo = foo; // or whatever ownership handling is needed.
[foo addObserver:self forKeyPath:@"bar" options:0 context:&fooObservanceContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == &fooObservanceContext) {
// handle change
} else {
// not my observer callback
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)dealloc
{
self.foo = nil; // removes observer
}
When using KVO you have to make sure that both objects, observer and observee, are alive as long as the observation is in place.
使用 KVO 时,您必须确保观察者和被观察者这两个对象都存在,只要观察到位。
When adding an observation you have to balance this with exactly one removal of the same observation. Don't assume, you're the only one using KVO. Framework classes might use KVO for their own purposes, so always check for the context in the callback.
添加观察时,您必须通过完全删除相同的观察来平衡这一点。不要假设,您是唯一一个使用 KVO 的人。框架类可能出于自己的目的使用 KVO,因此请始终检查回调中的上下文。
One final issue I'd like to point out: The observed property has to be KVO compliant. You can't just observe anything.
我想指出的最后一个问题是:观察到的属性必须符合 KVO。你不能只是观察任何东西。
回答by Rayfleck
Part of the NSKeyValueObserving protocol is this:
NSKeyValueObserving 协议的一部分是这样的:
- (void *)observationInfo
which should list the observers.
这应该列出观察者。
EDITUseful for debugging only.
EDIT仅用于调试。
回答by Honey
I underestand this an objective-c question. But since lots of people use Swift/objective-c together, I thought I point out the advantage of the Swift4 new API over older versions of KVO:
我理解这是一个客观的问题。但是由于很多人同时使用 Swift/objective-c,我想我想指出 Swift4 新 API 相对于旧版本 KVO 的优势:
If you do addObserver
multiple times for KVO, then for each change you'll get the observeValue
as many as the current number of times you've added yourself as the observer.
如果您addObserver
对 KVO执行多次,那么对于每次更改,您将获得与observeValue
您将自己添加为观察者的当前次数一样多的次数。
- And to remove yourself you haveto call
removeObserver
as many times as you added. - Removing it more than you've added will result in a crash
- 要删除自己,您必须调用
removeObserver
与添加的次数相同的次数。 - 删除的次数超过添加的次数会导致崩溃
The Swift4 observe
is far smarter and swiftier!
Swift4observe
更智能、更快捷!
- If you do it multiple times, it doesn't care. It won't give multiple callbacks for each change.
- And only one
invalidate
of thetoken
is enough. invalidat
ing it before beginning to observer or more times that that you've doneobserve
will not result in a crash
- 如果你多次这样做,它不在乎。它不会为每次更改提供多个回调。
- 并且只要其中
invalidate
之一token
就足够了。 invalidat
在开始观察之前或在您已经完成的更多次之前执行它observe
不会导致崩溃
So to specifically answer your question, if you use the new Swift4 KVO, you don't need to care about it. Just call invalidate
and you're good. But if you're using the older API then refer to Nikolai's answer
所以具体回答你的问题,如果你使用新的Swift4 KVO,你就不用关心了。打个电话invalidate
就好了 但是,如果您使用的是较旧的 API,请参阅 Nikolai 的回答