2012-08-11 77 views
23

在用于注册关键值通知的以下方法中,上下文参数有什么用处。文件只是将其表示为任意数据。关键值观察中的上下文参数的重要性

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

有人可以提供一些线索什么是其背后的目的...

感谢

+0

可能重复(http://stackoverflow.com/questions/1625575/parameters-from-observevalueforkeypathofobjectchangecontext) – 2012-08-11 19:06:23

回答

73

我希望这个解释是不是太过抽象理解。

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

现在您决定让MyViewController使用KVO观察对self.viewcenter财产的更改。所以,你正式加入自己作为观察员:

- (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的观察员。如果是这样,那么你可能有两个问题:

  1. 当视图的中心改变时,你可能会被调用两次。
  2. 当您以观察者身份离开自己时,您可能还会删除UIViewController的KVO注册。

您需要一种方法将自己注册为与UIViewController的KVO注册不同的观察者。这就是context的论点。你需要传递一个值为context,你绝对相信UIViewController而不是使用作为context参数。当您取消注册时,您再次使用相同的context,以便您只删除注册,而不是UIViewController的注册。在observeValueForKeyPath:ofObject:change:context:方法中,您需要检查context以查看该消息是针对您还是针对您的超类。

确保使用context的其中一种方法是,在MyViewController.m中创建一个static变量。当你注册和注销,像这样使用它:在您的observeValueForKeyPath:...方法

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

然后,检查它像这样:

- (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的MyViewController的子类,它不会干扰您的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]; 
    } 
} 
[参数从observeValueForKeyPath:ofObject变化:背景:]的
+0

感谢很多关于你的详细解释真的很感激。一段时间以来,我一直困惑着为什么这个参数很重要,并且你的回答能够澄清它。 :) – rustylepord 2012-08-12 08:19:24

+0

你好我可以使用上下文来设置一些对象,稍后当通知来检索它时o根据存储在上下文中的值执行一些特定的任务。 – Sandeep 2012-11-26 15:06:34

+9

+1精彩的解释。 (一个单独的警告:'UIView'的属性不符合KVO,不能观察'view.center'。) – 2013-10-08 15:48:59