Variable windowNibName

On page 25, we got rid of:

let mainWindowController = MainWindowController(windowNibName:“MainWindowController”)

and replaced it with:

let mainWindowController = MainWindowController()

Then we overrode the variable windowNibName

So my question is: Is windowNibName the designated initializer for MainWindowController (given the fact that its inherited from NSWindowController)? Because since we removed the code in the parentheses, how does MainWindowController know to use the overridden variable?

windowNibName is a variable declared in the MainWindowController class:

[code]class MainWindowController: NSWindowController {

override var windowNibName: String? {
return “MainWindowController”
}

...

}[/code]

And windowNibName’s type is String(actually optional String, which just means that besides a String you can also assign nil to the variable). I don’t think a variable can be an initializer, much less a designated initializer.

Because you are calling MainWindowController() that means somewhere you are calling an initialization method defined as:

init() { //do stuff here }

Previously, when you called MainWindowController(windowNibName:“MainWindowController”) that meant that somewhere you were calling a method defined as:

init(windowNibName: String) { //do stuff here }

MainWindowController is the instance being created, so its class is checked first for instance variables and methods before going up the inheritance hierarchy. Here is a simple example of that:

class Animal {
    func speak() {
        "Animal"
    }
}

class Squirrel: Animal {
/*
    override func speak() {
        "Squirrel"
    }
*/
}


Squirrel().speak()   //=> "Animal"

If you uncomment the Squirrel override, then the output will be different.

Now, add a variable:

[code]class Animal {
var sound: String {
return “roar”
}

func speak() {
    sound
}

}

class Squirrel: Animal {
/*
override var sound: String {
return “squeak”
}
*/

}

Squirrel().speak() //=> “roar”[/code]

Once again, if you uncomment the override the output will be different. The Squirrel instance created by Squirrel() is the thing calling the speak() method, so the Squirrel class is checked first for the methods and instance variables.

A similar thing is happening with the MainWindowController:

[code]class MyNSWindowController {

var windowNibName: String? {
      return nil
}

init() {
    loadXibFile(windowNibName)  
}

func loadXibFile(xibFileName: String?) {
    if let fileName = xibFileName {
        //unarchive xib file
        "Finished unarchiving xib file: \(fileName)"
    }
    else {
        "Don't try to load xib file"
    }
 }

}

class MainWindowController: MyNSWindowController {
override var windowNibName: String? {
return “MainWindowController”
}

}

class AppDelegate {
init() {
let mainWindowController = MainWindowController()
}

}

AppDelegate()
[/code]

In the init() method in MyNSWindowController, the line:

is equivalent to:

And when MainWindowController is created by the init() method, then inside the init() method self is equal to the MainWindowController instance. You can see that by adding a println() statement:

init() { println(“self is equal to: \(self)” ) //=>"self is equal to: __lldb_expr_50.MainWindowController" self.loadXibFile(self.windowNibName) }

Both loadXibFile() and windowNibName are first looked up in self’s class, i.e. the MainWindowController class, and if not present there, then in MainWindowController’s parent class, i.e. the MyNSWindowController class.

I finally understand it now. Thank you so much.

An excellent explanation 7stud7stud!