I want to initialize a window controller object from a nib file, quite easy right? But I simply can't get it to work.
According to my previous experience in ObjC, I've written down the following code:
init() {
super.init(windowNibName: "SplitWindowController")
}
And in the app delegate file, I simply init and displays the window:
var myWindowController: MyWindowController = MyWindowController()
myWindowController.showWindow(self)
myWindowController.window.makeKeyAndOrderFront(nil)
But the compiler gives me this error: Must call a designated initializer of the superclass 'NSWindowController'
. And according to the Swift version of NSWindowController
definition, there are only 3 designated initializers, namely init()
, init(window)
, init(coder)
. I don't know what to do next. Shall I build a NSCoder
from a nib file, which I don't know how to do?
You were almost there. You can indeed override init()
as a convenience initialiser in a manner that is equivalent to the Obj-C code you got used to:
import Cocoa
class MyWindowController: NSWindowController {
override convenience init() {
self.init(windowNibName: "<xib name>")
}
}
Note that you are calling init(windowNibName:)
on self
, because init()
being a convenience initialiser, you still inherit all the initialisers from the superclass. From documentation:
Rule 1: A designated initializer must call a designated initializer from its immediate superclass.
Rule 2: A convenience initializer must call another initializer from the same class.
Rule 3: A convenience initializer must ultimately call a designated initializer.
Also, as @weichsel mentioned above, make sure you set the class of the File's Owner
to your subclass of NSWindowController
(in the example above, that would be MyWindowController
) and then connect its window
outlet with the window itself.
That being said, I'm not sure why is compiler asking for the override
keyword to be added. Though NSWindowController
is a subclass of NSResponder
, which defines an init()
, the following code compiles without issue even though it implements an equivalent inheritance hierarchy:
class A {
init() { }
}
class B: A {
init(Int) {
super.init()
}
convenience init(String) {
self.init(5)
}
}
class C: B {
convenience init() {
self.init("5")
}
}
NSWindowController
has 2 designated initializers:
init(window: NSWindow!)
init(coder: NSCoder!)
When creating a subclass, you should invoke the designated initializer of its superclass. Recent versions of Xcode enforce this. Either via built-in language mechanism (Swift) or via NS_DESIGNATED_INITIALIZER
macro (Objective-C).
Swift additionally requires that you call the superclasses designated initializer when you override a convenience initializer.
From the "Initialization: Designated Initializers and Convenience Initializers" section of Swift Programming Guide:
If the initializer you are overriding is a convenience initializer, your override must call another designated initializer from its own subclass, as per the rules described above in Initializer Chaining.
In your case, you should probably override init(window: NSWindow!)
and call super's counterpart from there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With