2

我需要KVO的一些帮助,我大约在那里的一半。我试图做的是在树控制器中的某些内容发生变化时触发一个方法。有关键值观察的帮助

所以我使用此代码注册为KVO。

[theObject addObserver: self 
      forKeyPath: @"myKeyPath" 
       options: NSKeyValueObservingOptionNew 
       context: NULL]; 

但是,当我正在观察的关键路径发生变化时,我该如何触发一种方法?

一个额外的问题,当我将自己添加为观察者我希望密钥路径是我的核心数据模型中的一个属性,我是否正确地做到了这一点?

回答

6

覆盖observeValueForKeyPath:ofObject:change:context:来调度您希望调用的方法。

@interface Foo : NSObject { 
    NSDictionary *dispatch; 
    ... 
} 
@end 
@implementation Foo 
-(id)init { 
    if (self = [super init]) { 
     dispatch = [[NSDictionary dictionaryWithObjectsAndKeys:NSStringFromSelector(@selector(somethingHappenedTo:with:)),@"myKeyPath",...,nil] retain]; 
     ... 
    } 
} 
... 
- (void)observeValueForKeyPath:(NSString *)keyPath 
      ofObject:(id)object 
      change:(NSDictionary *)change 
      context:(void *)context 
{ 
    SEL msg = NSSelectorFromString([dispatch objectForKey:keyPath]); 
    if (msg) { 
     [self performSelector:msg withObject:object withObject:keyPath]; 
    } 
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
} 
... 

有关详细信息,请参阅“Receiving Notification of a Change”。

+0

“NSDictionary dispatch;”应该是“NSDictionary * dispatch;”,否则就是好。 – 2009-10-02 16:24:23

+0

D'oh。固定。另外,将“performSelector”更改为“performSelector:withObject:withObject”,以获得更普遍有用的方法。 – outis 2009-10-02 16:28:57

+0

有一个额外的问题,当我将自己添加为观察者时我想让关键路径成为我的核心数据模型中的一个属性,我是否正确地做了这件事? – Joshua 2009-10-02 16:34:07

4

您应该实现这一点,它就会被调用时的keyPath变化:

(void)observeValueForKeyPath:(NSString *)keyPath 
        ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context; 

更多信息here

+0

OffTopic:是的,错误的问题:( – genesis 2011-10-10 22:21:47

5

我建议你看看谷歌工具箱For Mac的GTMNSObject+KeyValueObserving.h类别或至少是由Michael Ash创建的博客post。基本上,做手动KVO权利是非常微妙和API建议的模式并不理想。将其他图层放在API上会更好(如GTMNSObject + KeyValueObserving),这使API更像NSNotification API,并隐藏了一些微妙的错误来源。

使用GTMNSObject + KeyValueObserving,你会做

[theObject gtm_addObserver:self 
       forKeyPath:@"myKeyPath" 
        selector:@selector(myCallbackSelector:) 
        userInfo:nil 
        options:NSKeyValueObservingOptionNew]; 

和你-myCallbackSelector:将被调用时,在@"myKeyPath"变化与GTMKeyValueChangeNotification类型的参数,它封装了所有你可能需要的相关信息的价值。

这样,您不必在observeValueForKeyPath:ofObject:change:context(实际上是由您的类别维护)的大调度表,或者不必担心使用指针的正确方法以避免与超级冲突/子类等

+0

看起来很有趣,我在哪里下载代码/框架? – Joshua 2009-10-02 17:25:16

+0

http://code.google.com/p/google-toolbox-for-mac/ 与提升C++库类似,GTM就是一个你想要的架构。他们建议你将你想要的文件/类直接包含到你自己的项目中。只有几个常见的包含。 – 2009-10-02 17:43:04

3

(这是一种技术,我在这里学到:http://www.bit-101.com/blog/?p=1999

您可以通过该方法在 '语境',像

[theObject addObserver:self 
      forKeyPath:@"myKeyPath" 
       options:NSKeyValueObservingOptionNew 
       context:@selector(doSomething)]; 

在observeValueForKeyPath方法..then ,你将它转换为SEL选择器类型,然后执行它。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    SEL selector = (SEL)context; 
    [self performSelector:selector]; 
} 

如果你想将数据传递到你可以使用“新”的关键在“变”字典中的doSomething方法,像这样:

[theObject addObserver:self 
       forKeyPath:@"myKeyPath" 
       options:NSKeyValueObservingOptionNew 
       context:@selector(doSomething:)]; // note the colon 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
    { 
     SEL selector = (SEL)context; 

     // send the new value of observed keyPath to the method 
     [self performSelector:selector withObject:[change valueForKey:@"new"]]; 
    } 


-(void)doSomething:(NSString *)newString // assuming it's a string 
{ 
     label.text = newString; 
}