来自笔尖的 NSWindowController 子类初始化不使用 -initWithCoder:?
Posted
技术标签:
【中文标题】来自笔尖的 NSWindowController 子类初始化不使用 -initWithCoder:?【英文标题】:NSWindowController subclass initialization from a nib doesn't use -initWithCoder:? 【发布时间】:2010-08-15 16:52:09 【问题描述】:我已将 NSWindowController 的自定义子类添加到我的 Cocoa 项目中,并将我的子类的一个实例添加到我的应用程序的 nib 中。我希望在加载 nib 时看到我对 -initWithCoder: 方法的覆盖,但事实并非如此。为了调试,我添加了一个常规的 -init 方法并在其上设置了一个断点——果然,我在加载 nib 时遇到了断点。
这实际上可以使一些事情对我来说更简单(例如设置 windowNibName),但我不明白为什么 Cocoa 会这样。我读过的所有文档都表明 -initWithCoder: 是我应该覆盖的地方。为什么这个案例有什么不同?
【问题讨论】:
为什么要把窗口控制器放到笔尖里?通常,您使用窗口控制器来加载 nib,并且窗口控制器将成为 nib 内容的文件所有者。 这个特殊的窗口控制器用于下拉到我的应用程序主窗口的工作表。通过使其成为它加载的 nib 的文件所有者,以及我的 MainMenu nib 中的***对象,我可以轻松地从任一位置建立到它的 IB 连接。它就像一个魅力。 :-) 【参考方案1】:我假设要在 Interface Builder 中实例化您的窗口控制器,您将一个通用的 NSObject
实例拖到 nib 文件中,然后将您的自定义 NSWindowController
子类分配为对象的类,对吗?如果是这样,那么我认为它们的主要区别在于您正在处理实例化通用对象而不是 IB 调色板之一中包含的自定义对象。
大多数情况下,当您使用 IB 创建和配置对象时,您在各种检查器中指定的设置会在保存 nib 文件时使用encodeWithCoder:
方法进行编码。然后,当您在应用程序中加载该 nib 文件时,这些对象将使用 initWithCoder:
方法进行初始化。
但是,在该通用对象实例的情况下,Interface Builder 不一定知道被实例化对象的类的任何信息。由于您可以指定任何要实例化的类名,因此如果您指定了一个 IB 没有通过调色板或框架加载的类,它就无法使用NSCoding
序列化该对象。所以我相信当你实例化一个像这样的通用对象时,它会使用init
而不是initWithCoder:
进行初始化,因为在保存 nib 文件时它没有使用encodeWithCoder:
进行保存。
我不知道这是否在任何地方都有记录,但我认为这就是您在那里看到差异的原因。我也不认为它是特定于 NSWindowController
的,而是在 IB 中实例化为通用 NSObject
的任何对象都会看到相同的行为,而不管具体的类是什么。
【讨论】:
我几乎按照你的描述做了……除了我在 IB 中使用类浏览器并将我的 NSWindowController 子类的一个实例拖到我的 nib 的顶层。正如您所描述的,这种行为是有意义的,它似乎是一个有用的功能。太糟糕了,没有更好的记录!【参考方案2】:我仍然没有正式的答案为什么 Cocoa 会这样,但在实际使用中似乎很方便。我已经使用以下 -init 方法定义了一个 NSWindowController 子类,它就像一个魅力。
- (id)init;
if ((self = [super initWithWindowNibName:@"MumbleMumbleSheet"]) != nil)
…
return self;
如果 -initWithCoder: 被调用,我将不得不弄清楚如何履行调用超级 -initWithCoder: 方法的隐含义务,并且仍然获得用于加载的正确 -windowNibName。这种方式更简单。
我仍然希望指向一些文档的指针,说这个类是不同的,并解释了为什么以及如何......但是在没有文档的情况下有经验证据。
【讨论】:
一个原因是 NSWindowController 不需要 xib。您实际上可以使用 IB 创建一个 NSWindowController 并将其窗口插座连接到您想要的任何窗口并“控制”它。但你是对的。我发现自己一直在做和你一样的事情。在 ios 上,视图控制器有一个约定:如果您的视图控制器类名为 XYZViewController,则在初始化时它会自动加载一个名为 XYZView(或类似名称)的 xib 文件。【参考方案3】:编码器方法用于已序列化并保存到文件的类。
你在这里做的是不同的。您正在将控制器类构建到可执行文件中。这意味着无需从文件中读取类本身,因为它是正在运行的应用程序二进制文件的一部分。
使用此控制器类时,您需要提供一个 init 方法,您可以在其中提供 nib 文件名。为什么?好吧,您将编译的类作为 exe 的一部分,但不知道 nib 文件是什么。这就是您提供这些知识的方式。
这样想。您的控制器类是 exe 的一部分。需要在它和 nib 文件之间建立一些链接。一种方法是扫描所有 nib 文件以查找对该控制器的引用。那将是低效的。在 init 中提供名称和所有引导程序。
换句话说,您从实验中学到了一些重要的经验。干得好,观察力如此之好。
【讨论】:
我应该说得更清楚一点:我正在从一个 nib 加载我的 NSWindowController 子类的这个实例(嗯,现在是 xib)。如果我们可以在此处包含图像,那就太好了,因为这样可以更轻松地描述准确的位置……以上是关于来自笔尖的 NSWindowController 子类初始化不使用 -initWithCoder:?的主要内容,如果未能解决你的问题,请参考以下文章
来自 NSWindowController Cocoa 的自定义视图
如果我加载一个笔尖而不将 xib 中的文件所有者作为 -loadNibNamed 中的所有者传递:所有者: