在以下方法中使用context参数有什么用于注册键值通知。文档只是将其表示为任意数据集。
addObserver:self forKeyPath:@"selectedIndex" options:NSKeyValueObservingOptionNew context:nil
有人能说清楚它背后的目的是什么......
答案 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}}的观察者。如果是,那么您可能会遇到两个问题:
center
的KVO注册。您需要一种方法将自己注册为与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