问题 在多个Storyboard场景中使用NSArrayController


我有一个使用故事板的基于Mac文档的核心数据应用程序。故事板具有以下布局:

Window Controller
    Split View Controller
        Table View Controller
        Text View Controller

My Core Data模型包含一个Chapter实体,它包含两个属性:title和contents。我希望表视图显示每个章节标题。文本视图显示所选章节的内容。

如果我使用的是xib文件,我会在xib文件中添加一个数组控制器。我将数组控制器绑定到File的所有者以访问我的NSPersistentDocument子类。我将表视图绑定到数组控制器的arrangeObjects属性,并将文本视图绑定到数组控制器的选择。

但随着故事板,事情变得更加复杂。我可以向表视图控制器添加一个数组控制器,将表视图绑定到数组控制器,并在表视图中显示章节标题。但是文本视图控制器无法绑定到该阵列控制器,因为阵列控制器位于另一个场景中。

如何在Interface Builder中添加数组控制器,以便表视图控制器和文本视图控制器都可以访问它并绑定到它?


7095
2017-11-05 01:17


起源

只需将它作为属性粘贴在app委托中......(主要是开玩笑。)但OSX故事板中父视图存在哪些关键路径? - stevesliva
NSViewController有一个parentViewController属性。但是,如果我将一个数组控制器添加到拆分视图控制器并使用parentViewController.arrayController.arrangedObjects的模型键路径将表视图列的Value绑定绑定到表视图控制器,应用程序崩溃说该类不符合KVC标准key arrayController。我将阵列控制器的插座添加到我的拆分视图控制器子类中,并将插座连接到我在IB中创建的阵列控制器,并发生同样的崩溃。 - Mark Szymczyk
我正在读这个...也许覆盖parentViewController getter返回具有arrayController属性的特定子类?但这很难看。 - stevesliva
我尝试重写parentViewController getter,最后得到一个空表。谢谢你的建议。我已经得出结论,目前无法与Mac故事板共享阵列控制器。也许Apple会在OS X 10.11中添加此功能。 - Mark Szymczyk


答案:


做这项工作的关键是拥有一个 NSArrayController 每个降序中的实例 NSViewController 子类并通过中央数据源(很可能是您的NSDocument子类)将它们绑定在一起。然后,您可以将此数据源设置为 NSViewController 子类 representedObject 通过你的下降传递它 控制器。这是一个带有一个故事板应用程序的例子 NSWindowController 它有一个内容视图控制器 NSSplitViewController 带有两个子视图控制器(主/细节设置):

class Document: NSDocument {

    var dataSource: DataSource? = DataSource()

    ...
}

class DataSource: NSObject, NSCoding {

    var items: [Item] = []
    var selectionIndexes: NSIndexSet = NSIndexSet()

    ...
}

class WindowController: NSWindowController {

    override var document: AnyObject? {
        didSet {
            if let document = self.document as? Document {
                self.contentViewController?.representedObject = document
            }
        }
    }

}

class SplitViewController: NSSplitViewController {

    override var representedObject: AnyObject? {
        didSet {
            for viewController in self.childViewControllers as! [NSViewController] {
                viewController.representedObject = representedObject
            }
        }
    }
}

诀窍是绑定 representedObject 每个降序视图控制器 NSArrayController 在故事板中。你只需要绑定NOT contentArray 但也是 selectionIndexes

结果是 selectionIndexes 两个下降 NSArrayControllers保持同步,因为它们通过中央数据源绑定(DataSource 上例中的子类)。

为了使这一点更加清晰,我创建了一个示例项目,在此处演示: https://github.com/acwright/StoryboardBindingsExample


16
2018-04-27 19:46



令人印象深刻。我下载了你的例子,它的确有效。我希望几个月前能得到这个答案。我放弃了为我当前的项目使用绑定,我没有回头,但是我将在未来使用故事板的项目中记住这个答案。 - Mark Szymczyk
谢谢!我即将放弃我正在开始的项目的绑定,但我觉得解决方案必须是可能的!然后我发现这真的只是让选择保持同步! :) - Aaron Wright
你有这个为Core Data工作吗?我对你所做的事情有类似的想法,但是虽然我可以得到选择索引并证明它是从一个场景更新的,但我总是在第二个场景中得到一个空的数组控制器。 - LighteningKid
没关系,它确实有效!关键似乎是将一个selectedIndexes变量放在Document.swift中,该变量被设置为每个NSViewController的representObject,因此您可以确保每个都获得相同的selectedIndexes。无论如何,您需要Document作为representObject,因此您可以为Core Data设置所有NSArrayControllers的managedObjectContext。 - LighteningKid
很棒的例子,即使使用没有绑定的故事板,这也很有帮助。 - Andrew