Данные Xcode9 Swift4.2 NSOutlineView NSTreeController

Я пытаюсь создать схему в приложении MacOS с несколькими уровнями, которые являются сводками для набора данных, хранящихся в SQLite3. У меня есть схема, работающая с древовидным контроллером с очень простым 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)

И это прекрасно работает, давая мне складной план:

введите здесь описание изображения

Но я понятия не имею, как добавить больше уровней или детей к детям. Я хочу иметь до четырех уровней в глубине схемы. У меня работают все сводки SQL, и я пробовал так много вариантов заполнения массивов и пытался создать словарь с данными, но безрезультатно. У меня есть children и childCount и isLeaf, установленные для всего, но древовидному контроллеру не нравится массив, жалующийся на то, что isLeaf не совместим с KVO. Мои данные в массиве выглядят так (не все данные, но достаточно, чтобы понять, что я делаю). Основной уровень и все последующие дочерние элементы основаны на приведенном выше классе модели Summary. Могу ли я просто преобразовать этот массив в словарь? Или я могу сделать его совместимым с KVO, добавив ключи в класс модели или что-то в этом роде? У меня есть все 4 уровня в отдельных массивах, которые я использую для построения результирующего массива, если это полезно:

введите здесь описание изображения

Я должен добавить, что у меня есть NSObject, определенный как NSMutableArray, и его содержимое привязано к treeController. Мой treeController привязан к каждой переменной в классе модели и на верхнем уровне имеет:

введите здесь описание изображения

Если я передам массив, который я построил, в TreeController, я получу следующую ошибку:

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

person Mooky    schedule 17.11.2018    source источник
comment
Совместим ли класс Summary KVO с ключами children, childCount и isLeaf?   -  person Willeke    schedule 18.11.2018
comment
@Willeke Единственное, что я знаю в этом отношении, это сделать переменные @objc dynamic.   -  person Mooky    schedule 18.11.2018
comment
Я думаю, что моя проблема с KVO связана с Interface Builder, где я могу что-то ввести неправильно. Мне удалось полностью отключить контроллер дерева и вообще отказаться от привязок, чтобы он работал по старинке. Я все еще хочу, чтобы KVO работал, поэтому я буду продолжать попытки.   -  person Mooky    schedule 18.11.2018


Ответы (1)


После сборки моего NSOutlineView без NSTreeController и получения всего, что работает, я все еще хотел вернуться к этому и реализовать treeController, чтобы воспользоваться преимуществами механизма сортировки, который он предоставляет. И я обнаружил, согласно моему последнему комментарию, что у меня было что-то не так в InterfaceBuilder, из-за чего он жаловался на соответствие KVO. У меня все правильно подключено, за исключением привязки Content Array к treeController. Здесь я привязал его к своему ViewController и добавил свой массив данных reportSummary в путь к ключу модели.

введите здесь описание изображения

Мне также больше не нужно было вручную добавлять массив данных в TreeController с помощью treeController.addObject(reportSummary). Как только это заработало, я смог реализовать сортировку, и все работает хорошо. Я должен отметить две вещи.

  1. Настройка сортировки в TreeController немного отличается от настройки в ArrayController, привязанном к TableView. В табличном представлении было достаточно указать, какие столбцы сортируются в инспекторе идентификации в IB. Но в сценарии layoutView мне также нужно было настроить привязки в IB к treeController и изменить ключ контроллера с arrangedObjects на sortDescriptors.

  2. При тестировании схемы, управляемой деревом, я столкнулся с проблемой, когда дважды щелкнул сводную строку. Я реализовал двойное действие в layoutView в IB, чтобы управлять расширением и свертыванием сводных разделов. Обратите внимание, что я читал об этом в потоке здесь, и кто-то упомянул, что вам нужно будет поддерживать несколько массивов и отслеживать индексы, потому что после свертывания или расширения строки изменяется номер строки всех последующих строк. Но я понял, что решение состоит в том, чтобы просто перебирать строки в обратном порядке и расширять или сворачивать их, возвращаясь вверх по дереву, начиная с outlineView.numberOfRows-1. Это работает хорошо, и наряду с двойным действием (щелчок) для расширения и свертывания я также добавил 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

И это все. Красиво работает сейчас.

person Mooky    schedule 25.11.2018