Objective c NSTreeController KVO通知意外未触发
我遇到了一些涉及Objective c NSTreeController KVO通知意外未触发,objective-c,swift,key-value-observing,key-value-coding,nstreecontroller,Objective C,Swift,Key Value Observing,Key Value Coding,Nstreecontroller,我遇到了一些涉及NSTreeController和KVO的问题NSTreeController的selectionIndexPaths属性被记录为KVO observable,当我直接观察它时,它工作正常。但是,如果我将NSTreeController的selectionIndexPath列为某个其他属性的依赖项,然后尝试观察,则不会在预期的时间触发通知 下面是我能想到的最短示例代码,以演示我的意思: import Cocoa class ViewController: NSViewContr
NSTreeController
和KVO的问题NSTreeController
的selectionIndexPaths
属性被记录为KVO observable,当我直接观察它时,它工作正常。但是,如果我将NSTreeController
的selectionIndexPath
列为某个其他属性的依赖项,然后尝试观察,则不会在预期的时间触发通知
下面是我能想到的最短示例代码,以演示我的意思:
import Cocoa
class ViewController: NSViewController {
// Our tree controller
@IBOutlet dynamic var treeController: NSTreeController!
// Some random property on my object; you'll see why it's here later
@objc dynamic var foo: String = "Foo"
// A quick-and-dirty class to give us something to populate our tree with
class Thingy: NSObject {
@objc let name: String
init(_ name: String) { self.name = name }
@objc var children: [Thingy] { return [] }
}
// The property that the tree controller's `Content Array` is bound to
@objc dynamic var thingies: [Thingy] = [Thingy("Foo"), Thingy("Bar")]
// Dependencies for selectionIndexPaths
@objc private static let keyPathsForValuesAffectingSelectionIndexPaths: Set<String> = [
#keyPath(treeController.selectionIndexPaths),
#keyPath(foo)
]
// This property should be dependent on the tree controller's selectionIndexPaths
// (and also on foo)
@objc dynamic var selectionIndexPaths: [IndexPath] {
return self.treeController.selectionIndexPaths
}
// Some properties to store our KVO observations
var observer1: NSKeyValueObservation? = nil
var observer2: NSKeyValueObservation? = nil
// And set up the observations
override func viewDidLoad() {
super.viewDidLoad()
self.observer1 = self.observe(\.selectionIndexPaths) { _, _ in
print("This is only logged when foo changes")
}
self.observer2 = self.observe(\.treeController.selectionIndexPaths) { _, _ in
print("This, however, is logged when the tree controller's selection changes")
}
}
// A button is wired to this; its purpose is to set off the
// KVO notifications for foo
@IBAction func changeFoo(_: Any?) {
self.foo = "Bar"
}
}
我已经关注这一点有一段时间了,我不明白为什么直接观察treeController.selectionIndexPaths
有效,但观察依赖于treeController的属性。selectionIndexPaths
无效。由于我总的感觉我对KVO及其工作原理有一个很好的掌握,所以我不能解释这一点,这真的让我很烦
有人知道这种差异的原因吗
谢谢 可能重复的
@interface Thingy: NSObject
@property (nonatomic, copy) NSString *name;
- (instancetype)initWithName:(NSString *)name;
@end
@implementation Thingy
- (instancetype)initWithName:(NSString *)name {
self = [super init];
if (self == nil) {
return nil;
}
self->_name = name;
return self;
}
- (NSArray *)children { return @[]; }
@end
void *ctxt1 = &ctxt1;
void *ctxt2 = &ctxt2;
@interface ViewController()
@property (nonatomic, strong) IBOutlet NSTreeController *treeController;
@property (nonatomic, copy) NSString *foo;
@property (nonatomic, copy) NSArray *thingies;
@end
@implementation ViewController
+ (NSSet *)keyPathsForValuesAffectingSelectionIndexPaths {
return [NSSet setWithObjects:@"treeController.selectionIndexPaths", @"foo", nil];
}
- (NSArray *)selectionIndexPaths {
return self.treeController.selectionIndexPaths;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.thingies = @[[[Thingy alloc] initWithName:@"Foo"], [[Thingy alloc] initWithName:@"Bar"]];
[self addObserver:self forKeyPath:@"selectionIndexPaths" options:0 context:ctxt1];
[self addObserver:self forKeyPath:@"treeController.selectionIndexPaths" options:0 context:ctxt2];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (context == ctxt1) {
NSLog(@"This only gets logged when I click the button");
} else if (context == ctxt2) {
NSLog(@"This gets logged whenever the selection changes");
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (IBAction)changeFoo:(__unused id)sender {
self.foo = @"Bar";
}
@end