Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c NSTreeController KVO通知意外未触发_Objective C_Swift_Key Value Observing_Key Value Coding_Nstreecontroller - Fatal编程技术网

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