Xcode9 Swift4.2 NSOutlineView NSTreeController数据

时间:2018-11-17 20:01:40

标签: xcode9 nsoutlineview swift4.2 nstreecontroller

我试图在MacOS应用程序中创建一个Outlineview,该应用程序具有多个级别,这些级别是SQLite3中保存的一组数据的摘要。我有一个Outlineview和一个树控制器一起工作,该树控制器具有一个非常简单的基于模型类的NSMutuableDictionary。

import Cocoa
class Summary: NSObject {
    @objc dynamic var name: String
    @objc dynamic var trades: Int
    @objc dynamic var avgPL: Double
    @objc dynamic var pandl: Double
    @objc dynamic var parent: String
    @objc dynamic var isLeaf: Bool
    @objc dynamic var childCount: Int
    @objc dynamic var children: [Summary] = []
    init(name: String, trades: Int, avgPL: Double, pandl: Double, parent: String, isLeaf: Bool,childCount: Int) {
        self.name = name
        self.trades = trades
        self.avgPL = avgPL
        self.pandl = pandl
        self.parent = parent
        self.isLeaf = isLeaf
        self.childCount = childCount
    }
    @objc func add(child: Summary) {
        children.append(child)
    }
}

我的简单示例数据是:

    let root: [String : Any] = ["name": "Overall","trades":5,"avgPL":200,"pandl":500,"parent":"","isLeaf": false,"childCount": 2 ]
    let dict: NSMutableDictionary = NSMutableDictionary(dictionary: root)
    let l2a = Summary(name: "L2a", trades: 3, avgPL: 100, pandl: 300, parent: "L1",isLeaf: true,childCount: 0)
    let l2b = Summary(name: "L2b", trades: 2, avgPL: 100, pandl: 200, parent: "L1",isLeaf: true,childCount: 0)
    dict.setObject([l2a,l2b], forKey: "children" as NSCopying)

我将字典传递给treeController:

treeController.addObject(dict)

这很好地给了我一个可折叠的轮廓:

enter image description here

但是我不知道如何为孩子增加更多的关卡或孩子。我想在大纲中最多包含四个级别。我已经完成所有的SQL摘要,并且尝试了很多填充数组的变体,并试图创建一个字典,其中的数据无济于事。我在所有对象上都设置了child和childCount和isLeaf,但是treecontroller不喜欢数组抱怨isLeaf不兼容KVO。我在数组中的数据看起来像这样(不是所有数据,但足以了解我在做什么)。主级和所有后续子级都基于上述Summary模型类。我可以简单地将此数组转换为字典吗?或者,是否可以通过将键添加到模型类或其他内容使其兼容KVO?如果有用,我会将所有4个级别都放在单独的数组中,以构建结果数组:

enter image description here

我应该补充一点,我有一个定义为NSMutableArray的NSObject,其内容绑定到treeController。我的treeController绑定到模型类中的每个变量,并且在顶层具有:

enter image description here

如果将建立的数组传递给treeController,则会出现以下错误:

Failed to set (contentViewController) user defined inspected property on (NSWindow): [<_TtGCs23_ContiguousArrayStorageC11outlinetest7Summary_ 0x604000445160> addObserver:forKeyPath:options:context:] is not supported. Key path: isLeaf

1 个答案:

答案 0 :(得分:0)

在没有NSTreeController的情况下构建NSOutlineView并使所有功能正常工作之后,我仍然想回到此并实现treeController以便利用其提供的排序机制。根据我的最后评论,我确实发现我在InterfaceBuilder中确实有问题,导致它抱怨KVO合规性。除了在TreeController上的Content Array绑定之外,我所有的接线都正确。在这里,我将其绑定到ViewController并将数据数组reportSummary添加到模型键路径。

enter image description here

我也不再需要使用treeController.addObject(reportSummary)将数据数组手动添加到treeController。一旦开始工作,我便可以实施排序,并且一切正常。我应该指出两点。

  1. TreeController上的排序设置与绑定到TableView的ArrayController上的排序设置略有不同。使用tableview,足以指定IB中的身份检查器中哪些列可排序。但是在outlineView场景中,我还需要在IB中设置到treeController的绑定,并将Controller Key从arrangedObjects更改为sortDescriptors

  2. 在测试我的树状大纲视图时,双击摘要行时遇到了问题。我已经在IB中的outlineView上实现了Double Action,以便控制摘要部分的扩展和折叠。请注意,我在这里阅读了有关在线程中执行此操作的信息,有人提到您将需要维护多个数组并跟踪索引,因为一旦折叠或展开一行,就会更改所有后续行的行号。但是我发现解决方案只是简单地以相反的顺序遍历行,并从outlineView.numberOfRows-1开始向上扩展或折叠行。这很好用,并且与Double Action(单击)一起展开和折叠,我还添加了一个NSSlider,它可以跟踪到展开级别,并让我折叠所有最低的级别,然后向上移动到树上,而不是单击每一行上的所有小箭头。当我实现treeController时,这崩溃了。我收到错误

  

无法转换类型为“ NSKVONotifying_NSTreeControllerTreeNode”的值

这行代码就是问题

let summary = reportOutline.item(atRow: x) as! Summary

我不得不将其更改为

let node = reportOutline.item(atRow: x) as! NSTreeNode
let summary = node.representedObject as! Summary

就是这样。现在工作精美。