帮助进行关键值观察

时间:2009-10-02 16:05:32

标签: objective-c cocoa core-data cocoa-bindings key-value-observing

我需要KVO的一些帮助,我差不多在那里。我正在尝试做的是在树控制器中的某些内容发生变化时触发一个方法。

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

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

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

另外一个问题,当我将自己添加为观察者时,我希望关键路径成为我的核心数据模型中的属性,我是否已正确完成?

4 个答案:

答案 0 :(得分: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”。

答案 1 :(得分:5)

我建议您查看Google工具箱For Mac的GTMNSObject+KeyValueObserving.h类别或至少Michael Michael的博客post。基本上,正确地进行手动KVO 非常是微妙的,并且API建议的模式并不理想。在API上放置一个其他层(如GTMNSObject + KeyValueObserving)会更好地使事情更像NSNotification API并隐藏一些微妙的错误来源。

使用GTMNSObject + KeyValueObserving,你可以

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

,当-myCallbackSelector:的值因类型为@"myKeyPath"的参数更改时,您的GTMKeyValueChangeNotification将被调用,该参数会封装您可能需要的所有相关信息。

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

答案 2 :(得分:4)

您应该实现此功能,并在密钥路径更改时调用它:

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

更多信息here

答案 3 :(得分:3)

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

您可以在“上下文”中传递该方法,例如

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

..然后在observeValueForKeyPath方法中,将其转换为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;
}