键值观察中使用的上下文参数是什么 [英] What is the context parameter used for in Key value observing
问题描述
在以下用于注册键值通知的方法中,上下文参数有什么用?文档只是将其表示为任意数据集.
What's the use of context parameter in following method which is used to register for key value notifications. The documentations just denotes it as arbitrary set of data.
addObserver:self forKeyPath:@"selectedIndex" options:NSKeyValueObservingOptionNew context:nil
有人可以阐明它背后的目的是什么吗...
Can somebody shed some light what's the purpose behind it ...
推荐答案
我希望这个解释不要太抽象以至于无法理解.
I hope this explanation isn't too abstract to understand.
假设您创建一个类MyViewController
,它是UIViewController
的子类.您没有UIViewController
的源代码.
Suppose you create a class MyViewController
, which is a subclass of UIViewController
. You don't have the source code of UIViewController
.
现在,您决定使MyViewController
使用KVO来观察对self.view
的center
属性的更改.因此,您应该适当地添加自己作为观察员:
Now you decide to make MyViewController
use KVO to observe changes to the center
property of self.view
. So you duly add yourself as an observer:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.view addObserver:self forKeyPath:@"center" options:0 context:NULL];
}
- (void)viewDidDisappear:(BOOL)animated {
[self.view removeObserver:self forKeyPath:@"center"];
[super viewDidDisappear:animated];
}
这里的问题是,您不知道UIViewController
是否还将自己注册为self.view
的center
的观察者.如果确实如此,那么您可能会遇到两个问题:
The problem here is that you don't know if UIViewController
also registers itself as an observer of self.view
's center
. If it does, then you might have two problems:
- 当视图中心改变时,您可能会被两次呼叫.
- 当您退出观察者身份时,您可能还会删除
UIViewController
的KVO注册.
- You might be called twice when the view's center changes.
- When you remove yourself as an observer, you might also remove
UIViewController
's KVO registration.
您需要一种不同于UIViewController
的KVO注册的方式将自己注册为观察者.这就是context
自变量的来源.您需要为context
传递一个值,您必须完全确定UIViewController
是 not (用作context
自变量).取消注册时,将再次使用相同的context
,以便仅删除您的注册,而不删除UIViewController
的注册.并且在您的observeValueForKeyPath:ofObject:change:context:
方法中,您需要检查context
以查看消息是给您的,还是给您的超类的.
You need a way to register yourself as an observer that is distinguishable from UIViewController
's KVO registration. That's where the context
argument comes in. You need to pass a value for context
that you are absolutely sure UIViewController
is not using as the context
argument. When you unregister, you use the same context
again so that you only remove your registration, not UIViewController
's registration. And in your observeValueForKeyPath:ofObject:change:context:
method, you need to check the context
to see if the message is for you, or for your superclass.
一种确保您使用context
的方式(没有使用其他任何方式)的一种方法是在MyViewController.m
中创建一个static
变量.注册和注销时使用它,如下所示:
One way to be sure you use a context
that nothing else uses is to create a static
variable in MyViewController.m
. Use it when you register and unregister, like this:
static int kCenterContext;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.view addObserver:self forKeyPath:@"center" options:0 context:&kCenterContext];
}
- (void)viewDidDisappear:(BOOL)animated {
[self.view removeObserver:self forKeyPath:@"center" context:&kCenterContext];
[super viewDidDisappear:animated];
}
然后在您的observeValueForKeyPath:...
方法中,像这样检查它:
Then in your observeValueForKeyPath:...
method, check it like this:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
if (context == &kCenterContext) {
// This message is for me. Handle it.
[self viewCenterDidChange];
// Do not pass it on to super!
} else {
// This message is not for me; pass it on to super.
[super observeValueForKeyPath:keyPath ofObject:object
change:change context:context];
}
}
现在,您可以保证不干扰超类的KVO(如果有的话).而且,如果有人制作了也使用KVO的MyViewController
子类,则不会干扰您的KVO.
Now you're guaranteed not to interfere with your superclass's KVO, if it does any. And if somebody makes a subclass of MyViewController
that also uses KVO, it won't interfere with your KVO.
也请注意,您可以为观察到的每个关键路径使用不同的上下文.然后,当系统通知您更改时,您可以检查上下文而不是检查密钥路径.测试指针是否相等比检查字符串是否相等要快一些.示例:
Note too that you can use a different context for each key path you observe. Then, when the system notifies you of a change, you can check the context instead of checking the key path. Testing for pointer equality is a little faster than checking for string equality. Example:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
if (context == &kCenterContext) {
[self viewCenterDidChange];
// Do not pass it on to super!
} else if (context == &kBackgroundColorContext) {
[self viewBackgroundDidChange];
// Do not pass it on to super!
} else if (context == &kAlphaContext) {
[self viewAlphaDidChange];
// Do not pass it on to super!
} else {
// This message is not for me; pass it on to super.
[super observeValueForKeyPath:keyPath ofObject:object
change:change context:context];
}
}
这篇关于键值观察中使用的上下文参数是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!