Подключение выводов 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
}
}
}