【问题标题】:NSWindowController clarification of understandingNSWindowController 澄清理解
【发布时间】:2010-09-10 09:00:15
【问题描述】:

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

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

一些问题:

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

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

谢谢, 劳丽

【问题讨论】:

    标签: cocoa nswindowcontroller cocoa-sheet


    【解决方案1】:

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

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

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

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

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

    WindowControllers 和 MainMenu.xib

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

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

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

    【讨论】:

    • 鉴于:“如果你真的需要一个窗口控制器作为你的主窗口,你不能把它放在 MainMenu.xib 中”,你会把它放在哪里?
    • 我的猜测是在 App Delegate 中。这就是我正在做的事情,但我无法找到说明这是正确行为的文档。
    【解决方案2】:

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

    不,MainMenu nib 归 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];
    }
    

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

    【讨论】:

    • 不需要在窗口上自定义 NSView 子类。来自文档:“如果委托响应消息的选择器,则默认实现将每条消息转发给委托”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多