Key值观察中使用的上下文参数是什么

时间:2012-08-11 18:20:44

标签: objective-c cocoa cocoa-touch key-value-observing

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

addObserver:self forKeyPath:@"selectedIndex" options:NSKeyValueObservingOptionNew context:nil

有人能说清楚它背后的目的是什么......

1 个答案:

答案 0 :(得分:77)

我希望这个解释不太抽象,不能理解。

假设您创建了一个类MyViewController,它是UIViewController的子类。您没有UIViewController的源代码。

现在,您决定让MyViewController使用KVO观察对center self.view属性的更改。所以你适当地加入自己作为观察者:

- (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的{​​{1}}的观察者。如果是,那么您可能会遇到两个问题:

  1. 当视图中心发生变化时,您可能会被调用两次。
  2. 当您以观察者身份移除自己时,您也可能会删除center的KVO注册。
  3. 您需要一种方法将自己注册为与UIViewController的KVO注册区别开来的观察者。这就是UIViewController参数的来源。您需要传递context的值,您绝对相信context 使用UIViewController参数。取消注册后,再次使用相同的context,这样您才能删除注册,而不是context的注册。在UIViewController方法中,您需要检查observeValueForKeyPath:ofObject:change:context:以查看该消息是针对您还是针对您的超类。

    确保使用其他任何其他用途的context的一种方法是在context中创建static变量。注册和取消注册时使用它,如下所示:

    MyViewController.m

    然后在您的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:...

    现在你保证不会干扰你的超类的KVO,如果有的话。如果有人创建了- (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