KVO:+ keyPathsForValuesAffecting <key>不适用于(子类)NSObjectController </key>

时间:2013-04-12 08:06:29

标签: objective-c cocoa key-value-observing nsarraycontroller nsobjectcontroller

我有一个KVO-able类(称之为Observee),affectedValue动态属性受affectingValue属性的影响。通过实现+keyPathsForValuesAffectingAffectedValue方法来定义属性之间的依赖关系。

将值设置为affectingValue会通知affectedValue已按预期更改,除非 OvserveeNSObjectController的子类。完整示例如下:

@interface Observee : NSObject // or NSObjectController
@property (readonly, strong, nonatomic) id affectedValue;
@property (strong, nonatomic) id affectingValue;
@property (strong, nonatomic) NSArrayController *arrayController;
@end

@implementation Observee

@dynamic affectedValue;
- (id)affectedValue { return nil; }

+ (NSSet *)keyPathsForValuesAffectingAffectedValue {
  NSLog(@"keyPathsForValuesAffectingAffectedValue called");
  return [NSSet setWithObject:@"affectingValue"];
}

@end

@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (strong, nonatomic) Observee *observee;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)notification {
  self.observee = [[Observee alloc] init];
  [self.observee addObserver:self
                  forKeyPath:@"affectedValue"
                     options:NSKeyValueObservingOptionNew
                     context:NULL];
  NSLog(@"setting value to affectingValue");
  self.observee.affectingValue = @42;
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
  NSLog(@"affected key path = %@", keyPath);
}

@end

该示例正常工作,并在Observee派生NSObject时输出如下:

keyPathsForValuesAffectingAffectedValue called
setting value to affectingValue
affected key path = affectedValue

但是当Observee派生NSObjectController时:

keyPathsForValuesAffectingAffectedValue called
setting value to affectingValue

(请注意,“受影响的密钥路径= affectedValue”不存在。)

似乎在两种情况下都会调用keyPathsForValuesAffectingAffectedValue,但在后一种情况下它是无操作的。

此外,涉及NSObjectController的(子类)实例的任何关键路径都不会影响其他关键路径,例如:

@implementation SomeObject

// `someValue` won't be affected by `key.path.(snip).arrangedObjects`
+ (NSSet *)keyPathsForValuesAffectingSomeValue {
  return [NSSet setWithObject:@"key.path.involving.anNSArrayController.arrangedObjects"];
}

@end

在这种情况下,如何声明关键路径之间的依赖关系?而且,为什么会发生这件事?

(是的,我知道will/didChangeValueForKey:和朋友,但是用一个(其他)设置器包围每个影响关键路径都很可怕,我想避免它。)

1 个答案:

答案 0 :(得分:6)

NSController及其子类充满了KVO“黑魔法”和意外行为。 (另一个例子,他们不尊重某些KVO选项,如NSKeyValueObservingOptionPrior)如果您希望它们表现得像KVO的“正常”对象,您会感到失望。它们主要用于支持Cocoa绑定。虽然乍一看绑定可能看起来只是KVO之上的语法糖,你可以看到(通过覆盖绑定对象的KVO支持方法并在其中设置断点),实际上在封面下面还有更多的内容而不是简单的KVO观察。

file bugs with Apple增加他们修复(或至少记录)这些问题/行为的可能性。