3
votes

I am new to Swift and trying to learn how to implement NSTreeController with NSOutlineView. I've been following several guides which shows such examples, but I keep getting an error. I followed step by step and/or try to run their source codes if available, but I was getting same error. I come to think there is some change in Swift 4 which makes these Swift 3 examples to produce error. As there are not many examples done in Swift 4, I decided I'd give a try by asking the question here.

The error I'm getting is:

this class is not key value coding-compliant for the key isLeaf.

I believe that error is coming from the key path set up for NSTreeController:

enter image description here

However I am not sure what needs to be done to fix the error.

I have simple model class called Year.

class Year: NSObject {

    var name: String

    init(name: String) {
        self.name = name
    }

    func isLeaf() -> Bool {
        return true
    }
}

My view controller looks like this.

class ViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {

    @IBOutlet weak var outlineView: NSOutlineView!
    @IBOutlet var treeController: NSTreeController!

    override func viewDidLoad() {
        super.viewDidLoad()

        addData()
        outlineView.delegate = self
        outlineView.dataSource = self
        }

    func addData() {
        let root = ["name": "Year", "isLeaf": false] as [String : Any]
    
        let dict: NSMutableDictionary = NSMutableDictionary(dictionary: root)
        dict.setObject([Year(name: "1999"), Year(name: "2000")], forKey: "children" as NSCopying)
        treeController.addObject(dict)
    }

    func isHeader(item: Any) -> Bool {
        if let item = item as? NSTreeNode {
            return !(item.representedObject is Year)
        } else {
             return !(item is Year)
        }
    }

    func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
        if isHeader(item: item) {
            return outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "HeaderCell"), owner: self)!
        } else {
            return outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "DataCell"), owner: self)!
        }
    }
}

When I run the program, it causes no issue, but when I expand the node to show the two children of the root, it is giving the error I mentioned above.

2

2 Answers

2
votes

Because is isLeaf is used in KVO by NSOutlineView, you have to add @objc in front of isLeaf function:

@objc func isLeaf() -> Bool {
    return true
}
2
votes

The class to which you are binding needs to be KVO compliant.

So, it needs to be a subclass of NSObject. And the objc runtime needs access.

One way to do this:

@objcMembers
class FileSystemItem: NSObject {

Or, you can annotate each field/function with @objc

Full Example