41

我曾多次在项目中使用过 NSWindowController,感觉我(非常)粗略地掌握了这个重要类背后的概念。我想用这篇文章来澄清/纠正我自己的理解,并希望能帮助其他学习者迈出理解的第一步。这是我发现最有用的一目了然的概念、概述和最佳实践,但文档中经常缺少这些内容。这是我对 NSWindowController 的看法(问题以粗体散布):

  • NSWindowController (NSWC) 子类(概念上)存在于每个窗口 nib 下方,充当用户界面元素和它们控制/表示的模型对象之间的粘合剂。基本上,应用程序中的每个窗口都应该有自己的 NSWC 子类。
  • nib 的文件所有者应始终是 NSWC 子类。MainMenu.xib 应用程序也是这样吗?
  • NSWCwindow属性应始终链接到 InterfaceBuilder 中的 NSWindow。
  • 您应该使用 覆盖“init”方法,[super initWithWindowNibName:]以便在您引用[mycontroller window]它时加载笔尖。MainMenu.xib 窗口的 NSWC 是否也应如此,即使它是在启动时打开的?
  • NSWC 不应该做太多繁重的工作——它应该简单地将消息传递给对象实例,并在 UI 中呈现这些对象。
  • 它可以使用绑定来修改 UI,或者充当表的委托等,或者通过在观察到更改时主动更改 UI 元素,或者以上任何一种的组合(您使用哪个似乎是一个问题味道,各方面都有利弊)。
  • NSWC 可以在必要时创建其他 NSWC 的实例(例如,当打开一次性子窗口时)。
  • 使用[mycontroller showWindow:nil]可在前面显示关联的窗口。如果您希望窗口显示为工作表,请使用以下内容:

    NSWindowController* mycontroller = [[MyController alloc] init];
    [NSApp beginSheet: [mycontroller window]
       modalForWindow: [self window] 
        modalDelegate: self 
       didEndSelector: @selector(didEndMySheet:returnCode:contextInfo:)
          contextInfo: nil];
    

didEndSelector:应该是父窗口的NSWC的一个方法,可以通过[sheet windowController]. - 关闭窗口调用performClose:NSWC 的窗口的方法。

一些问题:

  • MainMenu 窗口的 NSWC 也应该是应用程序委托,还是应该是不同的类?
  • 同样,主要 NSWC 应该处理文件(拖放和打开),还是应该将其传递给应用程序委托,或者这只是一个品味问题?

如果这是不好的做法,或者完全是错误的,请纠正我。我希望澄清我对 NSWindowController 的理解,因此任何补充(以最佳实践、经验、陷阱的形式)都将受到高度赞赏。

谢谢,劳里

4

2 回答 2

30

窗口控制器实际上是做什么用的?

窗口控制器是从 NIB 文件加载窗口和管理在 NIB 中分配的资源的内存的工具。在此之前,NSWindowControllers基本上必须为每个窗口编写相同的代码或发明自己的窗口控制器类。

当然,它们也是模型/视图/控制器意义上的控制器,因此它们是将视图从窗口连接到模型对象的正确位置。为此,他们通常需要充当视图对象的委托或数据源。所以你完全正确地理解了这部分。

窗口控制器也是代码重用的工具。它可以很容易地将窗口控制器类和它的 XIB/NIB 放到另一个项目中并在那里使用它。

所以是的,NIB 中的每个窗口都应该由窗口控制器拥有,但有一个例外。实际上,这只是一个好的代码的指导方针,没有任何强制执行它。

WindowControllers 和 MainMenu.xib

MainMenu.xib是另一回事,你不能使用窗口控制器。这个NIB被加载,NSApplication所以这必须是它的“文件所有者”。无法在NSApplication和 NIB 之间获取窗口控制器。在那里也没有必要使用窗口控制器进行内存管理,因为应用程序对象在程序的整个运行时都存在,所以当它被释放时它不必从 NIB 中清理它的资源。

如果您确实需要主窗口的窗口控制器,则不能将其放在MainMenu.xib.

我希望这有帮助。关于窗口控制器可能还有很多话要说

于 2010-09-10T11:33:39.257 回答
7

MainMenu.xib 应用程序也是这样吗?

不,MainMenu nib 归 NSApplication (加载它的人)所有。

MainMenu.xib 窗口的 NSWC 是否也应如此,即使它是在启动时打开的?

不,NSApplication 根据您的应用程序文件的“NSMainNibFile”属性加载主笔尖。(它恰好在模板 Xcode 项目中被预先设置为“MainMenu”。)如果你想更改它的名称,然后在那里更改它(并重命名你的 nib 文件)。(顺便说一句:此属性也可以在 Xcode 4 中目标的“摘要”视图中更改。)

MainMenu 窗口的 NSWC 也应该是应用程序委托,还是应该是不同的类?

NSMainNibFile nib 的所有者是加载它的 NSApplication 实例,并通过关联该实例的任何委托。这些都不是 NSWC 子类。

同样,主要 NSWC 应该处理文件(拖放和打开),还是应该将其传递给应用程序委托,或者这只是一个品味问题?

没有“主 NSWC”(app/app-delegate 是 NSMainNibFile 的控制器)。

所有拖放操作都由 NSWindow 或 NSView 子类处理。我通常使用一个特殊的 NSWindow 或 NSView 子类,它只是将所有拖放方法传递给委托。例如:

- (unsigned int) draggingEntered:sender
{
    return [[self delegate] draggingEntered:sender];
}

这样,我可以将所有窗口/视图代码一起保存在它们各自的控制器中(由它们的 nib 所有者确定)。而且由于窗口/视图特定代码在控制器中(不是 NSWindow/NSView 子类),不同类型的 NSWindows/NSViews 都可以使用相同的拖放子类。

于 2011-04-09T17:58:00.817 回答