1

设置

我有一个NSTreeController子类。它有一个名为的属性selectedProject,它是自定义的,并在标题中声明如下:

@property (nonatomic, readonly) LPProject *selectedProject;

在私有实现中就像这样:

@property (nonatomic, readwrite, assign) LPProject *selectedProject;

至关重要的是,在我selectedProject在 TreeController 中修改的每一个点,我都会检查生成的 setter/getter。我从不直接修改 iVar。

基本上,这个属性存在的原因是因为没有键入的 normalselectedObjectsselectionproperties,NSTreeController而且我知道这个 TreeController 将始终只管理 LPProject 对象并且一次只能选择一个项目,我想要一个干净的 iVar使用,而不是不断获取 selectedObjects,检查是否有,获取数组中的第一个对象等。


LP项目

LPProjectNSManagedObjectCore Data 的自定义子类。它有一个名为 的属性enabled。此属性是一个 BOOL,由 NSNumber 表示。它的 getter/setter 由 Xcode 生成。


问题

在几个控制器中,我尝试观察对象的enabled属性selectedProject,如下所示:

[_myTreeController addObserver:self 
                    forKeyPath:@"selectedProject.enabled" 
                       options:0 
                       context:NULL];

我已经验证了 KVO 通知在selectedProject更改时到达(并因此selectedProject.enabled发生更改)。但是,当只有enabled属性发生变化时selectedProject(即选定的项目本身保持不变),KVO 通知不会到达。

但是,如果我改为以这种方式订阅:

[_myTreeController addObserver:self 
                    forKeyPath:@"selection.enabled" 
                       options:0 
                       context:NULL];

它完美地工作。当enabled更改并selectedProject保持不变时,KVO 通知到达。

我对此感到困惑,因为selectedProject它符合 KVO,而且我觉得 keypath.enabled应该可以工作。

任何人都可以阐明这一点吗?我错过了什么?

4

1 回答 1

1

我不知道您如何以及何时更新selectedProject属性,但是由于selection基于 - 的方法按预期工作(不仅如此),我建议您从(作为代理,也是 KVO )selectedProject创建派生属性):selectedObjectsselectionselectedObjects

// tell Cocoa which property changes directly affect selectedProject
+ (NSSet*)keyPathsForValuesAffectingSelectedProject {
    return [NSSet setWithObject:@"selectedObjects"];
}

- (LPProject*)selectedProject {
    // you might need to do some isKindOfClass checks if not all nodes are LPProject
    return self.selectedObjects.first;
}

标头属性声明保持不变,如果您提供 setter,则不需要实现声明。

这样做的美妙之处在于,运行时会在更改时自动发送 KVO 通知selectedProject属性selectedObjects,使用最少的胶水代码。

于 2016-01-27T19:56:31.070 回答