键值观察中使用的上下文参数是什么 [英] What is the context parameter used for in Key value observing

查看:70
本文介绍了键值观察中使用的上下文参数是什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下用于注册键值通知的方法中,上下文参数有什么用?文档只是将其表示为任意数据集.

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.viewcenter属性的更改.因此,您应该适当地添加自己作为观察员:

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.viewcenter的观察者.如果确实如此,那么您可能会遇到两个问题:

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:

  1. 当视图中心改变时,您可能会被两次呼叫.
  2. 当您退出观察者身份时,您可能还会删除UIViewController的KVO注册.
  1. You might be called twice when the view's center changes.
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆