启动基于Cocoa文档的应用程序首先显示选择窗口

时间:2010-10-11 02:57:55

标签: cocoa xib cocoa-bindings document-based

这似乎应该很容易但我必须遗漏一些东西。我有一个基于文档的应用程序。我还构建了一个新的XIB,它有一个NSTableView和三个按钮,我打算显示以前的文件列表。我希望在应用程序首次启动时显示此XIB而不是文档窗口。一旦用户选择旧文件或点击“新建”按钮,我希望然后转到文档窗口。这是非常常见的,我经常看到使用过。

在我试图实现这项工作时,我修改了project-info.plist文件,并将主NIB文件基本名称从MyDocument更改为我的选择XIB名称。这会导致应用程序显示“选择”窗口而不是“MyDocument”窗口。到目前为止似乎没有问题。

在我的选择窗口中,我已经为此XIB设置了我的表视图和一个数组控制器以及一个自定义窗口控制器。我已将文件所有者设置为新的窗口控制器,并将窗口控制器的窗口属性绑定到窗口,将Window的委托属性绑定到文件所有者以及“选择”,“取消”和“新建”按钮。 NSApplication没有任何限制。但奇怪的是,当我运行这个应用程序时,似乎想要将这些控制器连接到NSApplication并出现错误(对于其他两个按钮也是如此):

无法将动作selectButton:连接到类NSApplication的目标

它还显示一个错误,即NSApplication不符合键值,因为该插座保存了对我的数组的引用。阵列控制器,窗口和按钮不绑定到NSApplication,而是绑定到新的Window Controller。我原本以为如果有任何问题就不会提到NSApplication而是提到控制器绑定的窗口控制器。

任何人都知道这里发生了什么?这是一个Target-Action问题,因为我将“主要NIB文件库名称”从“主菜单”更改为“选择”?如果我不应该改变这个,那么如何让Cocoa允许我在显示文档窗口之前显示选择屏幕?

非常感谢任何帮助。 罗布

1 个答案:

答案 0 :(得分:9)

IB中文件所有者类的设置只是建议性的;它允许IB仅显示该类实例提供的出口和操作。它并不强制文件所有者将是该类的实例,因为文件的所有者不是笔尖的一部分。

文件所有者是加载笔尖的对象。 这必然意味着它位于笔尖之外,并且笔尖中的任何内容都不能确定任何内容。对于MainMenu笔尖,其文件所有者 - 加载MainMenu笔尖的对象 - 是NSApplication实例。因此,即使您告诉IB它不是应用程序,您连接到MainMenu笔尖中的文件所有者的所有内容都已连接到应用程序对象。

该应用程序是MainMenu笔尖的所有者 - 无论您告诉IB什么 - 不是错误。该应用程序始终是MainMenu笔尖的所有者。这是正常和正确的;你不能改变它,不应该试图改变它,也不需要改变它。

简而言之,这个错误就是你使用一个笔尖用于两个非常不同的目的。

你应该让MainMenu笔尖独自一人 - 仅包含MainMenu,你的自定义文档控制器(我稍后会介绍),以及你的app委托 - 并将之前的文档窗口移动到一个单独的笔尖中,由前一个文档窗口控制器拥有。为了让窗口控制器成为此笔尖的所有者,您需要让窗口控制器加载它。你必须在代码中这样做 - 你不能在IB或plist中设置它。

在应用程序的委托中,实例化并拥有窗口控制器。听起来你做了一个自定义的NSWindowController子类,所以你可以覆盖它的init让它自己发送initWithWindowNibName:消息来加载和拥有这个nib。然后,只需使用allocinit从app delegate创建窗口控制器。

这将摆脱控制台消息,并确保按钮实际上连接到窗口控制器(因为它们连接到文件的所有者,通过此更改,它将是窗口控制器)。

让您的应用委托通过向窗口控制器发送applicationOpenUntitledFile:消息来响应showWindow:。这将使前一个文档窗口在用户通常创建新文档时出现。

如果您想支持创建文档的常用方法(即允许新文档工作),请实现applicationDidFinishLaunching:applicationShouldHandleReopen:hasVisibleWindows:,而不是applicationOpenUntitledFile:。确保没有文档打开,如果是这种情况,请显示您的窗口。

您还应该创建NSDocumentController的自定义子类,并使您的文档控制器成为该实例,并在该类中实现addDocument:removeDocument:以重新显示之前的文档窗口最后打开的文档已关闭,并在打开文档时将其隐藏。