Подключение выводов NSSplitView с использованием раскадровки

У меня есть NSSplitView, который управляет иерархией сверления. Родительская/левая сторона отображает группы, а дочерняя/правая сторона получает уведомление о том, что выбор группы изменился, и обновления для отображения дочерних элементов.

Однако: при создании NSSplitView с использованием раскадровки, создаются 3 сцены: один для самого разделенного представления и один для каждого из экземпляров справа/слева NSViewController.

Проблема заключается в том, что у меня есть два контроллера, которые также действуют как элементы NSTableViewDataSource, а родительский контроллер должен иметь IBOutlet для дочернего контроллера, чтобы он мог обеспечить прямое уведомление о том, что выбор изменился.

Но! Поскольку эти контроллеры находятся в разных сценах, я не могу их подключить. Я также не могу перемещать их до родительской сцены для разделенного вида, потому что тогда они не имели бы доступа к выходам NSTableView. (Также таблицы не будут ссылаться на контроллеры в качестве делегатов/источников данных.)

Нужно ли здесь использовать NSNotification? Это кажется таким косвенным и желательным, и я не нашел подхода на основе Mac на Mac.

enter image description here

Ответ 1

Новый класс NSSplitViewController и NSTabViewController - это то, что Apple вызывает контейнерные контроллеры. вы можете получить ссылки на другие контроллеры в контейнере, используя новое свойство в NSViewController

@property (readonly) NSViewController *parentViewController
@property (copy) NSArray *childViewControllers

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

myChildTableController = [self.parentViewController childViewControllers][1];

или наоборот из вашего контроллера детского стола.

myParentTableController = [self.parentViewController childViewControllers][0];

Ответ 2

Как вы говорите, раскадровки на OS X (и iOS до этого) не позволят вам подключать IBOutlets между сценами, поэтому вам нужно передать действия каким-то другим способом.

Я бы настроил свойства actions/delegates в методе awakeFromNib любого из трех контроллеров. В этот момент все NSSplitView и его дочерние контроллеры будут созданы и подключены.

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

Ответ 3

Вы не обязательно хотите использовать NSSplitViewController. Вместо этого просто перетащите NSSplitView в основной вид вашей раскадровки.

Как объяснил Кори в своем ответе, новый NSSplitViewController и NSTabViewController имеют методы доступа к родительскому и дочернему контроллерам. Это полезно, если вы действительно хотите разделить свой интерфейс на разные сцены раскадровки.

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

enter image description here

Ответ 4

У меня была такая же проблема, и я нашел обходное решение. Это не очень элегантно и не позволяет подключать розетки к раскадровке, но это позволяет создавать отношения, идентичные тем, у которых IBOutlets.

Ключом является реализация одноэлементного класса:

import Foundation
import Cocoa

class SplitViewConnector {
    static let sharedInstance = SplitViewConnector()

    var masterController:NSViewController?
    var detailController:NSViewController?
}

Теперь в awakeFromNib методе вашего главного контроллера вы можете установить основную связь и, аналогично, вы можете установить связь для вашего контроллера детали.

Если, например, ваш главный контроллер должен иметь прямое отношение к вашему контроллеру деталей, вы также можете его реализовать. Предполагая, что класс вашего главного контроллера YourViewController, и свойство для доступа к вашему контроллеру деталей называется myDetail, оно будет выглядеть так:

var masterController:YourViewController? {
    didSet {
        self.assignDirectConnections()
    }
}

var detailController:NSViewController? {
    didSet
        self.assignDirectConnections()
    }
}

func assignDirectConnections() {
    if let master = self.masterController {
         if let detail = self.detailController {
            master.myDetail = detail
         }
    }
}