0

In my project an NSTreeController is bound to an NSOutlineView(cocoa binding). For some reason I can't use NSPredicate to filter data from Core Data. So I tried to override arrangedObjects of NSTreeController, but the overriding arrangedObjects has not even been fired. (I set a debugging breakpoint inside it.) The code compiles well and I've already changed the instance to my CleanTreeController. I only found an unanswered question asked a decade ago in the mailing list.

// Subclass of NSTreeController
class CleanTreeController: NSTreeController {
    init() {
        // This gets called.
        super.init(content: nil)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    override var arrangedObjects: Any {
        let oldArranged = super.arrangedObjects

        let selector = NSSelectorFromString("childNodes")

        guard let oldChildren = (oldArranged as! NSObject)
                            .perform(selector).takeUnretainedValue() as? [NSTreeNode]
        else
        {
            return oldArranged
        }

        let children = oldChildren.filter { (treeNode) in
            //... do some filtering
        }

        return TreeNodeProxy(with: children)
    }
}

// Homemade NSTreeNodeProxy
class TreeNodeProxy : NSObject {

    fileprivate var rootNode : NSTreeNode

    init(with children : [NSTreeNode]) {
        self.rootNode = NSTreeNode()
        self.rootNode.mutableChildren.addObjects(from: children)
    }

    @objc(childNodes)
    var children: [NSTreeNode]? {
        return rootNode.children
    }

    @objc(descendantNodeAtIndexPath:)
    func descendant(at indexPath: IndexPath) -> NSTreeNode? {
        return rootNode.descendant(at: indexPath)
    }
}

I've found

The value returned by NSTreeController's arrangedObjects method is opaque. You should only observe this property to determine that a change has occurred.

in the doc. So how can NSOutineView consume arrangedObjects without reading it (directly)?

LShi
  • 1,500
  • 16
  • 29
  • 1
    I tried this and `arrangedObjects` is called. Maybe it's easier to override the `content` setter? – Willeke Mar 21 '17 at 16:16
  • Thanks. Just overrided the initializers for debugging, one of them gets called. This is weird. – LShi Mar 22 '17 at 02:24
  • I made an vanilla project for test, and it's the same: the `arrangedObjects` getter is not called when the app starts. (I bound things up programmatically, not in the xib. It shouldn't make any difference I guess.) However I just found that after removing the displayed objects, the arrangedObjects did get fired. I will look into it to see what made the difference. – LShi Mar 24 '17 at 05:13
  • I did bind everything in the xib in my test app and `arrangedObjects` is not called when the app starts. I assumed `arrangedObjects` wasn't called because there are no objects but it isn't called with objects either. – Willeke Mar 24 '17 at 11:39

1 Answers1

0

Set fetchPredicate of the NSTreeController in the xib or in code.

Willeke
  • 14,578
  • 4
  • 19
  • 47