KVO:+ keyPathsForValuesAffecting <Key>不能与NSObjectController的(子类)一起使用

uas*_*asi 5 cocoa objective-c key-value-observing nsarraycontroller nsobjectcontroller

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

设置一个值以affectingValue通知affectedValue 已按我的预期更改, 除非 Ovservee是它的子类NSObjectController.完整示例如下:

@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
Run Code Online (Sandbox Code Playgroud)

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

keyPathsForValuesAffectingAffectedValue called
setting value to affectingValue
affected key path = affectedValue
Run Code Online (Sandbox Code Playgroud)

但是在Observee派生时NSObjectController:

keyPathsForValuesAffectingAffectedValue called
setting value to affectingValue
Run Code Online (Sandbox Code Playgroud)

(请注意,"受影响的密钥路径= 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
Run Code Online (Sandbox Code Playgroud)

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

(是的,我知道will/didChangeValueForKey:和朋友一起,但是用一个(另一个)设置器来包装每一个影响关键路径是可怕的,我想避免它.)

ipm*_*mcc 6

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

向Apple提交错误,以增加他们修复(或至少记录)这些问题/行为的可能性.