我正在尝试在Swift中启动一个基于Cocoa项目的新文档,并希望创建一个子类NSWindowController
(如Apple的基于文档的应用程序指南中所推荐的).在ObjC中,您将创建一个NSWindowController
子类的实例,该子类发送initWithWindowNibName:
消息,相应地实现,调用超类方法.
在斯威夫特init(windowNibName)
仅作为一种方便的初始化,类的指定初始化NSWindowController
就是init(window)
这显然想让我在一个窗口中通过.
我不能super.init(windowNibName)
从我的子类调用,因为它不是指定的初始化器,所以我显然必须实现convenience init(windowNibName)
,而这又需要调用self.init(window)
.但是,如果我只有我的nib文件,如何访问nib文件的窗口以发送到该初始化程序?
您需要覆盖NSWindowController
(init()
,init(window)
和init(coder)
)的所有三个指定初始值设定项,或者不覆盖它们中的任何一个,在这种情况下,您的子类将自动继承init(windowNibName)
,所有其他便利初始值设定项,您将能够使用超类的便捷初始化程序构造它:
// this overrides none of designated initializers class MyWindowController: NSWindowController { override func windowDidLoad() { super.windowDidLoad() } } // this one overrides all of them // // Awkwardly enough, I see only two initializers // when viewing `NSWindowController` source from Xcode, // but I have to also override `init()` to make these rules apply. // Seems like a bug. class MyWindowController: NSWindowController { init() { super.init() } init(window: NSWindow!) { super.init(window: window) } init(coder: NSCoder!) { super.init(coder: coder) } override func windowDidLoad() { super.windowDidLoad() } } // this will work with either of the above let mwc: MyWindowController! = MyWindowController(windowNibName: "MyWindow")
这由语言指南中的"初始化/自动初始化程序继承"涵盖:
但是,如果满足某些条件,则会自动继承超类初始值设定项.实际上,这意味着您不需要在许多常见场景中编写初始化程序覆盖,并且可以在安全的情况下以最小的努力继承您的超类初始化程序.
假设您为在子类中引入的任何新属性提供默认值,则适用以下两个规则:
规则1 如果您的子类没有定义任何指定的初始值设定项,它会自动继承其所有超类指定的初始值设定项.
规则2 如果您的子类提供了所有超类指定初始值设定项的实现 - 通过按照规则1继承它们,或者通过提供自定义实现作为其定义的一部分 - 那么它会自动继承所有超类便捷初始值设定项.
您可以简单地覆盖windowNibName
属性并返回硬编码字符串,而不是覆盖任何init方法.这允许您调用基本的vanilla init方法来创建窗口控制器.
class WindowController: NSWindowController { override var windowNibName: String! { return "NameOfNib" } } let windowController = WindowController()
我更喜欢这个而不是调用,let windowController = WindowController(windowNibName: "NameOfNib")
因为nib的名称是一个实现细节,它应该完全封装在窗口控制器类中,并且永远不会暴露在外面(而且它更容易调用WindowController()
).
如果要向init方法添加其他参数,请执行以下操作:
在您的自定义init方法调用中super.init(window: nil)
.这将NSWindowController
与windowNibName
属性进入init .
重写所需的init(coder: NSCoder)
方法以配置对象或只是调用fatalError()
禁止其使用(运行时为albiet).
class WindowController: NSWindowController { var test: Bool override var windowNibName: String! { return "NameOfNib" } init(test: Bool) { self.test = test super.init(window: nil) // Call this to get NSWindowController to init with the windowNibName property } // Override this as required per the class spec required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented. Use init()") // OR self.test = false super.init(coder: coder) } } let windowController = WindowController(test: true)
我只有一个类方法可以解决此问题,该方法调用便捷初始化程序,修改自定义变量,然后返回新对象。
因此,Objective C init
方法如下所示:
//Class.h @class PPPlugInInfo; @interface PPPlugInInfoController : NSWindowController //... - (id)initWithPlugInInfo:(PPPlugInInfo *)plugInfo; //... @end //Class.m #include "Class.h" @interface PPPlugInInfoController () @property (strong) PPPlugInInfo *info; @end @implementation PPPlugInInfoController - (id)initWithPlugInInfo:(PPPlugInInfo *)plugInfo; { if (self = [self initWithWindowNibName:@"PPPlugInInfoController"]) { self.info = plugInfo; } return self; } @end
这是我做Swift版本的方法:
class PPPluginInfoController: NSWindowController { private var info: PPPlugInInfo! class func windowControllerFromInfo(plugInfo: PPPlugInInfo) -> Self { var toRet = self(windowNibName:"PPPlugInInfoController") toRet.info = plugInfo return toRet } }