Cocoa OS X 绑定和非平凡数据模型



这个项目是在Cocoa & Swift for Mac OS X中创建一个编辑器工具,用于编辑一个重要的数据结构。 精简的架构如下所示:

Game
    title : String
    [ Room ]
Room
    roomKey : String
    roomName : String
    roomDescription : String
    [ Object ]
    [ Exit ]
Object
    objectDescription: String
Exit 
    destinationRoomKey : String
    sourceRoomKey : String

当前的实现 - 第三次复飞 - 有一个Document.xib文件(该应用程序是基于文档的),并且我将NSObjectController连接到文档加载的基本游戏对象,并将NSArrayController连接到游戏对象房间数组。 房间有一个NSObject控制器。 我还没有完成对象或出口。

视图由基本根视图控制器处理,该控制器在视图层次结构中上下移动时交换子视图。 在根游戏状态的视图上,单击在房间列表的表视图中滑动的"编辑"按钮。 单击其中一个房间行中的按钮可在具有自己的控制器的房间详细信息视图中滑动。

这一切都运行良好。 我已经挂接了房间的对象控制器,以便它使用接口生成器绑定将房间数组的选定房间作为其对象。 我可以这样做,因为我在一个 XIB 文件中拥有所有视图、视图控制器和数据模型控制器。

但是:现在我正在将游戏对象添加到此组合中,并且 XIB 文件变得非常笨拙。 我真的觉得我想在单独的 XIB 文件中执行此操作,但是当我以前尝试这样做时,我无法将控制器相互连接。 我尝试手动编写代码来加载和保存数据,同时控制器显示和删除其视图,但这很容易出错。 到目前为止,我得到的最优雅和最强大的结果是使用这个 XIB 方法。

我查看了用于绑定的编程 API,但不了解如何使其工作,或者如何发现密钥路径的外观。 我想如果可以编程方式进行绑定,您可以将不同的部分放在不同的 XIB 中并在加载时进行绑定。 但我找不到任何成功做到这一点的例子,这似乎是一条通往疯狂的道路。

目前,我对 Swift 及其与 Cocoa 和 Objective-C 的关系没有任何问题,所以如果有人在 Objective-C 或 Swift 中得到答案,我很乐意听到他们。 我没有把 Swift 作为这个问题的关键词,因为它不是问题的一部分。

我已经看到了关于分层模型的StackOverflow答案,以及我目前正在做的事情,所以它没有帮助。 问题是,当有几层主细节时,这种方法会变得笨拙。

我还看到了关于共享控制器的 StackOverflow 答案,这是我之前尝试过的,也是我遇到那里描述的问题的地方,如果您在 NIB 中指定控制器对象,它将实例化为独立对象。 因此,为什么我目前有巨大的死亡NIB方法。

我可以将这个问题的标题设为"无法使编程绑定工作",但我不确定这是否是正确的方法。

肯定有人以前做过让一个非平凡的数据模型与可可一起工作的工作吗?

您的辅助 NIB 应该是查看 NIB,它们的所有者将是 NSViewController 或自定义子类的实例。这有一个representedObject属性。NIB 及其视图控制器类应被视为独立的、理论上可重用的组件。也就是说,从理论上讲,NIB可以在多个上下文中用于表示特定类型的对象。因此,通常不希望连接到 UI 的其他部分或其控制器,除了知道加载此视图以表示哪个对象。

在 NIB 中,您可以使用通过representedObject的模型密钥路径绑定到文件的所有者,也可以添加绑定到文件所有者representedObjectNSObjectController,然后通过控制器密钥选择绑定视图。

当您加载这样的辅助 NIB 时,您必须将其representedObject设置为它应该表示的对象,取自数组控制器的选择。这应该在代码中完成,大概是决定它需要加载 NIB 并这样做的相同代码。

如果 UI 的设计使得详细信息视图需要触发最好在更高级别处理的行为(例如,Room 视图需要安排将 Exit 视图滑入窗口,而不是作为其自身视图的子视图),则详细信息视图控制器应定义委托协议并实现委托属性。例如,房间视图控制器的委托协议可能具有方法 -roomViewDidChangeSelectedExit: 。房间视图控制器将在其委托上调用它,传递self 。您可以将某个协调控制器(可能是窗口控制器)设置为详细信息视图的委托。


我不清楚"细节"视图和"主"视图是否同时可见。也就是说,用户是否可以在不先备份的情况下更改详细信息视图要显示的对象?如果是这样,有几种方法。

可以在加载视图时以编程方式设置绑定。这将是加载详细信息视图的控制器的责任。这不是详图视图控制器的责任。这没有更高层次的视角和知识来设置绑定。无论如何,你可以这样做:

[detailViewController bind:@"representedObject" toObject:self.arrayController withKeyPath:@"selectedObjects.firstObject" options:@{ }];

请务必在释放详细信息视图控制器之前调用-unbind:

另一种方法是使用非 Bindings 方法简单地观察更改的选择,并在触发的代码中设置新representedObject。例如,如果主视图允许用户在表视图中选择项目,则可以设置表视图的委托(几乎可以肯定已经完成)并实现-tableViewSelectionDidChange:。在该委托方法中,查询新选择的项目并将其分配给detailViewController.representedObject

最新更新