Cocoa OS X Bindings和非平凡数据模型

时间:2015-01-10 15:07:57

标签: macos cocoa model-view-controller binding

这个项目是在Cocoa& amp;创建一个编辑工具。 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到游戏对象阵列的房间。有一个房间的NSObjectController。我还没有完成对象或退出。

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

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

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

我查看了程序化API的绑定,但无法理解如何使其工作,或者如何发现关键路径的样子。我想如果可以以编程方式进行绑定,可以将不同的部分放在不同的XIB中,并在加载时进行绑定。但我找不到任何人成功做到这一点的例子,这似乎是疯狂的道路。

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

我已经看过StackOverflow answer about hierarchical models,以及我目前正在做的事情,所以它没有帮助。问题是,当有几层主从细节时,这种方法变得笨拙。

我也看过StackOverflow answer about sharing controllers,这是我之前尝试过的,我遇到了那里描述的问题,如果你在NIB中指定一个控制器对象,它将被实例化为一个独立的对象。因此,为什么我目前拥有巨大的NIB-of-death方法。

我可以提出这个问题的标题"无法使程序化绑定工作"但我还是不确定那是不是正确的做法。

当然有人已经完成了使用Cocoa制作非平凡数据模型的工作吗?

1 个答案:

答案 0 :(得分:1)

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

在NIB中,您可以使用经过representedObject的模型密钥路径绑定到文件所有者,也可以添加绑定到文件所有者的NSObjectController&# 39; s representedObject然后使用控制器键选择将您的视图绑定。

当您加载这样的辅助NIB时,您必须将其representedObject设置为它应该代表的对象,取自阵列控制器的选择。这应该在代码中完成,可能与决定它需要加载NIB的代码相同。

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


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

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

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

请务必在详细视图控制器发布之前调用-unbind:

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