Getting NSTreeController Data on NSOutlineView selection

1.2k views Asked by At

I've built an NSOutlineView that gets dynamically updated data from an NSTreeController and that all works fine. What I can't seem to do is work backwards from there based on a user selection in the NSOutlineView.

    var deviceStore = [TreeNode]()

is my backing datastore that is updated in real-time it is an array of Device Objects, which may )or may not) contain an array of Service objects as children.

This all works. But when I select a row in the Outline View, I need to work my way back to the original object in the deviceStore -- or, at the very least, get the displayed data from the OutlineView so that I can walk the deviceStore to find the original item.

What I've got is func outlineViewSelectionDidChange(_ notification: Notification) {} which is called when a selection is made, and I can, from that, extract the NSTreeController TreeNode via treeController.selectedNodes but from there, I am in the weeds. The selectedNodes is the complete array of the selected Node, so if it's a child (leaf) node, it includes its parent node, and all its siblings.

Give then Table shown here: OutlineView

The selectedNodes array looks like this:

<NSTreeControllerTreeNode: 0x6080000c4590>, child nodes {
    0:<NSTreeControllerTreeNode: 0x6000000ca6b0>, child nodes {
        0:<NSTreeControllerTreeNode: 0x6000000caf70>, child nodes {}
        1:<NSTreeControllerTreeNode: 0x6000000cafe0>, child nodes {}
        2:<NSTreeControllerTreeNode: 0x6000000cb050>, child nodes {}
    }
    1:<NSTreeControllerTreeNode: 0x6080000d1790>, child nodes {
        0:<NSTreeControllerTreeNode: 0x6000000cce80>, child nodes {}
    }
}

And the selectedIndex is 4.

I can't see how to get back to what, in my data model, would be deviceStore[0].serviceStore[2] from this information.

If I could retrieve the value in the Service ID column from the selected Row, I could simply walk the deviceStore tree to find it.

I'm sure there's a simply, elegant, easy way to do this that I just haven't found yet, but being new to NSTreeControllers and NSOutlineViews I'm lost.

3

There are 3 answers

0
Davidgs On BEST ANSWER

I was never able to actually get back to the TreeController backing-store data baed on where the user clicks in the TreeView. What I was able to do was to work backwards to the data though.

func outlineViewSelectionDidChange(_ notification: Notification) {
    let selectedIndex = (notification.object as AnyObject).selectedRow!
    let selCol1 = outlineView.view(atColumn: 0, row: selectedIndex, makeIfNecessary: false)?.subviews.last as! NSTextField
    let selCol2 = outlineView.view(atColumn: 1, row: selectedIndex, makeIfNecessary: false)?.subviews.last as! NSTextField

    let devName = selCol1.stringValue
    let devID = selCol2.stringValue
...
}

I could then 'walk' the deviceStrore array until I found the devName and devID in it, and deal with it accordingly.

Probably not the most elegant solution, but at least it finally works.

2
Bogdan Farca On

You may try to access directly the associated object(s) like this:

let selectedService = treeController.selectedObjects.first as? Service

The docs are here.

also make sure your NSTreeController is correctly configured to use your class' objects:

enter image description here

Alternatively (if you want to work directly with your data source) you may want to get the index path of the selected object in the NSTreeController:

var selectionIndexPath: IndexPath? { get }
0
Peter Ahlberg On

I use following with Core data,

func outlineViewSelectionDidChange(_ notification: Notification) {
    let item = outlineView.item(atRow: outlineView.selectedRow) as! NSTreeNode
    let fileItem = item.representedObject as! FileItemMO

    // Do what you need to do with object fileItem

}