objective-c - KVO : +keyPathsForValuesAffecting<Key> doesn't work with (subclass of) NSObjectController

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

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

设置一个值给affectingValue 通知affectedValue 已经按照我的预期改变了,unless 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

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

keyPathsForValuesAffectingAffectedValue called
setting value to affectingValue
affected key path = affectedValue

但是当 Observee 派生 NSObjectController 时:

keyPathsForValuesAffectingAffectedValue called
setting value to affectingValue

(注意“affected key path = 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: 和 friend ,但是用(另一个)setter 包裹每个影响关键路径是很糟糕的,我想避免它。)

最佳答案

NSController 及其子类充满了 KVO“黑魔法”和意想不到的行为。 (再举一个例子,它们不遵守某些 KVO 选项,例如 NSKeyValueObservingOptionPrior)如果您希望它们在 KVO 方面表现得像“普通”对象,您将会感到失望。它们的存在主要是为了支持 Cocoa 绑定(bind)。虽然乍一看绑定(bind)可能看起来只是 KVO 之上的语法糖,但您可以看到(通过覆盖绑定(bind)对象的 KVO 支持方法并在其中设置断点)实际上在幕后还有很多事情要做而不是简单的 KVO 观察。

file bugs with Apple以增加他们解决(或至少记录)这类问题/行为的可能性。

关于objective-c - KVO : +keyPathsForValuesAffecting<Key> doesn't work with (subclass of) NSObjectController,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15966158/

相关文章:

objective-c - 将 id 转换为指向 NSError 指针的指针 (NSError **)

objective-c - Cocoa-Touch - 将文本文件加载到数组中

objective-c - NSWindow 设置 View

ios - 导致没有 dealloc 被调用的通知

ios - 为什么在 observeValueForKeyPath 中启动此请求时获取的请求不是最新的?

ios - 实现有问题的 KeyValue Observation

ios - 具有后台模式和来电通知的 SIP 应用程序

ios - 以编程方式模拟UITextField的键盘返回键

ios - 本地化 Info.plist 后出现构建错误

objective-c - Cocoa 应用程序 - 安全问题