2

我需要一些关于 KVO 的帮助,我已经完成了一半。我要做的是在树控制器中的某些内容发生更改时触发一个方法。

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

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

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

一个额外的问题,当我将自己添加为观察者时,我希望关键路径成为我的核心数据模型中的一个属性,我做得对吗?

4

4 回答 4

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

有关详细信息,请参阅“接收更改通知”。

于 2009-10-02T16:16:55.100 回答
5

我建议您查看 Google Toolbox For Mac 的GTMNSObject+KeyValueObserving.h类别,或者至少查看启发它的 Michael Ash的博客文章。基本上,手动做 KVO 是非常微妙的,API 建议的模式并不理想。最好在 API 上放置一个其他层(如 GTMNSObject+KeyValueObserving),这会使事情更像NSNotificationAPI 并隐藏一些细微错误的来源。

使用 GTMNSObject+KeyValueObserving,你会做

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

并且当 at 的值随 type 的参数更改时,您-myCallbackSelector:将被调用,该参数封装了您可能需要的所有相关信息。@"myKeyPath"GTMKeyValueChangeNotification

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

于 2009-10-02T16:37:36.273 回答
4

你应该实现它,它会在 keypath 改变时被调用:

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

更多信息在这里

于 2009-10-02T16:16:13.820 回答
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 方法,您可以使用 'change' 字典中的 'new' 键,如下所示:

[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;
}
于 2010-08-13T12:32:03.630 回答