Использование основных данных и привязок какао в нескольких сценах раскадровки - PullRequest
0 голосов
/ 19 июня 2020

У меня есть приложение для macOS, не основанное на документе, которое использует привязки какао, основные данные и раскадровки. Модель данных проста ...

List
  Name
  Players; to many relationship to Player

Player
  Name
  Lists; to-many relationship to List

И раскадровка имеет следующий макет ...

Window Controller
  Split View Controller
    View Controller
      Table View
    View Controller
      Table View
    View Controller
      Label

Я пытаюсь понять, как правильно поделиться контекст управляемого объекта в трех контроллерах представления и синхронизировать два представления таблиц и метку c. Используя ответ в этот вопрос У меня есть что-то, что почти функционально, хотя и немного отличается, потому что у меня есть отношение «многие ко многим», поэтому мне нужно дополнительное табличное представление.

Я установил промежуточный объект контроллера, который имеет ссылку на контекст управляемого объекта, два массива индексов, используемых для синхронизации различных контроллеров массивов c, и начальные дескрипторы сортировки.

class Controller: NSObject {
  @objc var moc = ...
  @objc var listSelectionIndexes = IndexSet()
  @objc var playerSelectionIndexes = IndexSet()
  @objc var sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
} 

Затем у меня есть подкласс NSSplitViewController, который я использую для внедрения этого контроллера в три контроллера представления ...

class SplitViewController: NSSplitViewController {
    private let controller = Controller()

    override func awakeFromNib() {
        super.awakeFromNib()
        children.forEach {
            $0.representedObject = controller
        }
    }
}

В крайнем левом контроллере у меня есть единственный контроллер массива, для которого установлено значение сохранить свой выбор и подготовить его содержимое и имеет следующие привязки ...

[Entity: List]
Selection Indexes ~> View Controller.self.representedObject.listSelectionIndexes
Managed Object Context ~> View Controller.self.representedObject.moc

и соответствующее табличное представление ...

Content ~> Array Controller.arrangedObjects
Selection Indexes ~> Array Controller.selectionIndexes
Sort Descriptors ~> Array Controller.sortDescriptors

В среднем контроллере у меня есть два массива контроллеры, которые оба настроены на сохранение своего выбора и подготовку своего содержимого и имеют следующие привязки ...

[Array Controller 1; Entity: List]
Selection Indexes ~> View Controller.self.representedObject.listSelectionIndexes
Managed Object Context ~> View Controller.self.representedObject.moc

[Array Controller 2; Entity: Player]
Content Set ~> Array Controller 1.selection.players
Selection Indexes ~> View Controller.self.representedObject.playerSelectionIndexes
Sort Descriptors ~> View Controller.self.representedObject.sortDescriptors
Managed Object Context ~> View Controller.self.representedObject.moc

и соответствующие g табличное представление, привязанное к контроллеру массива 2 ...

Content ~> Array Controller 2.arrangedObjects
Selection Indexes ~> Array Controller 2.selectionIndexes
Sort Descriptors ~> Array Controller 2.sortDescriptors

Наконец, самый правый контроллер представления, у меня есть единственный контроллер массива, который настроен на подготовку своего содержимого, но не сохранить выделение и имеет следующие привязки ...

[Entity: Player]
Selection Indexes ~> View Controller.self.representedObject.playerSelectionIndexes
Sort Descriptors ~> View Controller.self.representedObject.sortDescriptors
Managed Object Context ~> View Controller.self.representedObject.moc

И метка имеет одну привязку ...

Value ~> Array Controller.selection.name

На этом снимке экрана вы можете видеть, что это почти работает ... enter image description here Я говорю почти , потому что, если я сортирую среднюю таблицу, используя ее заголовок, я теряю самый правый выбор, даже если средний выбор сохраняется ... enter image description here Кроме того, если я нажимаю на уже выбранную строку, она не обновляет третью панель - мне нужно выключить, а затем снова включить, чтобы обновить ее. Выбор любой другой строки работает должным образом.

Если я затем включу Сохранить выделение на контроллере массива в самом правом контроллере представления a выделение сохраняется, но оно неправильный, потому что похоже, что порядок сортировки не синхронизируется ... enter image description here

Как я могу исправить эту проблему: порядок сортировки и выбор справа- самый лучший контроллер представления?

И более общий вопрос: действительно ли это лучший подход ? Кажется, ужасно много сантехники - почти похоже на взлом - просто чтобы иметь возможность синхронизировать c данные между сценами с использованием привязок, и меня также беспокоит стоимость использования нескольких Контроллеры массивов содержат одинаковую информацию, особенно если записей были тысячи.

1 Ответ

0 голосов
/ 25 июня 2020

Вместо добавления контроллеров массивов для восстановления выбранного списка или плеера проще передать выбранный список и плейер другому контроллеру представления. Требуется некоторый код для изменения выбранного списка и проигрывателя при изменении выбора в табличном представлении.

class Controller: NSObject {
    @objc dynamic var moc = …
    @objc dynamic weak var selectedList : List?
    @objc dynamic weak var selectedPlayer : Player?
}

Самый левый контроллер представления списка:

Контроллер представления является делегатом табличное представление.

class ListViewController: NSViewController, NSTableViewDelegate {

    @IBOutlet var arrayController: NSArrayController!

    func tableViewSelectionDidChange(_ notification: Notification) {
        let controller = representedObject as! Controller
        if arrayController.selectedObjects.count == 1,
            let list = arrayController.selectedObjects[0] as? List {
            controller.selectedList = list
        }
        else {
            controller.selectedList = nil
            controller.selectedPlayer = nil // tableViewSelectionDidChange isn't called on the Player table view
        }
    }

}

Контроллер представления среднего игрока:

Контроллер представления является делегатом табличного представления.

class PlayerViewController: NSViewController, NSTableViewDelegate {
    
    @IBOutlet var arrayController: NSArrayController!

    func tableViewSelectionDidChange(_ notification: Notification) {
        let controller = representedObject as! Controller
        if arrayController.selectedObjects.count == 1,
            let player = arrayController.selectedObjects[0] as? Player {
            controller.selectedPlayer = player
        }
        else {
            controller.selectedPlayer = nil
        }
    }
    
}

Привязать набор содержимого проигрывателя Контроллер массива View Controller.representedObject.selectedList.players

Самый правый контроллер детального представления:

Привязать значение текстового поля к View Controller.representedObject.selectedPlayer.name

...