Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize a NSWindowController in Swift?

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?

like image 917
Void Main Avatar asked Jul 04 '14 15:07

Void Main


2 Answers

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")
    }
}
like image 80
Milos Avatar answered Sep 28 '22 07:09

Milos


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.

like image 41
Thomas Zoechling Avatar answered Sep 28 '22 07:09

Thomas Zoechling