8
votes

I have a tree-like model I'd like to show in an NSOutlineView using an NSTreeController.

I was able to set up the bindings and everything works fine as long as I use the NSTreeController's insert and remove functions to change my model tree. If I try to insert or remove from the model tree directly, in some cases the NSOutlineView isn't updating.

If I insert an object into an expanded group of objects, it works:

Inserting node

New node showing

But if I try to add the first object to a node, that had no children before, nothing happens. The disclosure triangle isn't appearing, so I can't expand it to see the new node.

Inserting new child

enter image description here

If I hover over that node with a new object, it is expanded and I can add the second child with no problems. But the triangle is still invisible:

enter image description here

Finally if I close the parent of all these nodes and open them again (triggering a reload) the triangle suddenly appears:

enter image description here

That's why I was wondering if I had to manually reload the NSOutlineView's rows to make the triangle visible, or if I'm messing up something? Thanks!!

UPDATE:

In my Node class I add a new child like this:

- (void)addChild:(MyNode *)child {
    [self willChangeValueForKey:@"childNodes"];
    [children addObject:child];
    [self didChangeValueForKey:@"childNodes"];
}

And I implemented these too (which I set in IB for my NSTreeController):

- (NSArray *)childNodes {
    return [NSArray arrayWithArray:children];
}

- (NSInteger)countOfChildNodes {
    return [children count];
}

- (BOOL)nodeIsLeaf {
    return [children count] < 1;
}

I know that this (especially childNodes) aren't very optimized, but I'm only experimenting at the moment as in the final version my children will be stored in a C array.

UPDATE 2:

I also tried sending KVO notifications for the other 2 properties too, but that didn't help either.

- (void)addChild:(MyNode *)child {
    NSLog(@"%@", NSStringFromSelector(_cmd));
    [self willChangeValueForKey:@"nodeIsLeaf"];
    [self willChangeValueForKey:@"countOfChildNodes"];
    [self willChangeValueForKey:@"childNodes"];
    [children addObject:child];
    [self didChangeValueForKey:@"childNodes"];
    [self didChangeValueForKey:@"countOfChildNodes"];
    [self didChangeValueForKey:@"nodeIsLeaf"];
}
1

1 Answers

2
votes

You have to make sure that all updates to your model are performed in a Key-Value Observing-compliant manner.

Cocoa Bindings Programming Topics: Troubleshooting Cocoa Bindings