objective-c - Key value observing中的context参数是做什么用的

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

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

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

有人可以阐明它背后的目的是什么......

最佳答案

我希望这个解释不会太抽象而难以理解。

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

现在你决定制作MyViewController使用 KVO 观察 center 的变化self.view的属性(property).因此,您正式将自己添加为观察员:

- (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 .如果是这样,那么您可能会遇到两个问题:

  1. 当 View 的中心发生变化时,您可能会被调用两次。
  2. 当您删除自己的观察员身份时,您可能还会删除 UIViewController的 KVO 注册。

您需要一种方法将自己注册为观察者,以区别于 UIViewController的 KVO 注册。那就是 context 的地方参数进来了。您需要为 context 传递一个值你绝对确定UIViewController 用作context争论。注销时,您使用相同的 context再次这样你只删除你的注册,而不是UIViewController的注册。在你的 observeValueForKeyPath:ofObject:change:context:方法,你需要检查context看看这条消息是给你的,还是给你的父类(super class)的。

确保使用 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:...方法,检查它是这样的:

- (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];
    }
}

现在您可以保证不会干扰父类(super class)的 KVO(如果有的话)。如果有人创建了 MyViewController 的子类也使用 KVO,它不会干扰您的 KVO。

另请注意,您可以为观察到的每个关键路径使用不同的上下文。然后,当系统通知您更改时,您可以检查上下文而不是检查关键路径。测试指针相等性比检查字符串相等性快一点。示例:

- (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];
    }
}

关于objective-c - Key value observing中的context参数是做什么用的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11916502/

相关文章:

objective-c - NSLog(...) 不正确的格式说明符会影响其他变量吗?

ios - 如何使用 Swift 以编程方式创建 UILabel?

iPhone ImageView序列动画

objective-c - NSOutlineView:为什么 shouldEditTableColumn: 被调用两次?

cocoa - Cocoa 中的高阶贝塞尔路径

iphone - 关于延迟加载的内存

cocoa-touch - 在 arm64 上使用 NSScanner 处理 CGFloat

iphone - 使用 iPhone API 拍照并将其传输到服务器

objective-c - 搜索大量文本的 iOS 应用

objective-c - 我该怎么办 "char *bufferData = new char[charSize];"