NSWindowController澄清理解

时间:2010-09-10 09:00:15

标签: cocoa nswindowcontroller cocoa-sheet

我在项目中多次使用过NSWindowController,感觉我对这个重要课程背后的概念非常粗略。我想对这篇文章做的是澄清/纠正我自己的理解,并希望帮助其他学习者迈出理解的第一步。这是我发现最有用的一目了然概念,概述和最佳实践,并且通常缺少文档。这是我对NSWindowController的看法(问题以粗体点缀):

  • NSWindowController(NSWC)子类(概念上)存在于每个窗口笔尖的下方,充当用户界面元素与它们控制/表示的模型对象之间的粘合剂。基本上,应用程序中的每个窗口都应该有自己的NSWC子类。
  • nib的文件所有者应始终是NSWC的子类。 即使是MainMenu.xib应用程序也是如此?
  • NSWC window属性应始终链接到InterfaceBuilder中的NSWindow。
  • 您应该使用[super initWithWindowNibName:]覆盖'init'方法,这样当您引用[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]访问和释放“mycontroller”。 - 要关闭窗口,请调用NSWC窗口的performClose:方法。

有些问题:

  • MainMenu窗口的NSWC是否也应该是应用程序代表,还是应该是另一个类?
  • 同样,主要NSWC应该处理文件(拖放和打开),还是应该传递给应用代表,还是仅仅是品味问题?

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

谢谢, 劳里

2 个答案:

答案 0 :(得分:30)

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

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

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

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

所以是的,来自NIB的每个窗口都应归窗口控制器所有,但有一个例外。实际上,这只是一个好代码的指南,没有任何强制执行它。

WindowControllers和MainMenu.xib

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

如果您确实需要主窗口的窗口控制器,则无法将其放在MainMenu.xib中。

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

答案 1 :(得分:7)

  

即使是MainMenu.xib应用程序也是如此?

不,MainMenu笔尖由NSApplication拥有(加载它的人)。

  

对于MainMenu.xib窗口的NSWC,情况也是如此,即使这是在启动时打开的吗?

不,NSApplication根据您的应用程序文件的“NSMainNibFile”属性加载主nib。 (它恰好在模板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];
}

这样我可以将所有窗口/视图代码保存在各自的控制器中(由其笔尖所有者确定)。并且因为窗口/视图特定代码在控制器(而不是NSWindow / NSView子类)中,所以不同类型的NSWindows / NSView都可以使用相同的drag-n-drop子类。