tags:

views:

45

answers:

3

I've added a custom subclass of NSWindowController to my Cocoa project, and added an instance of my subclass to my application's nib. I expected to see my override of the -initWithCoder: method called when the nib was loaded, but it was not. To debug, I added a regular -init method and set a breakpoint on it — and sure enough I hit the breakpoint while loading the nib.

This could actually make some things simpler for me (e.g. setting the windowNibName) but I don't understand why Cocoa is behaving this way. All the documentation I have read suggests that -initWithCoder: is where I should be overriding. Why is this case any different?

A: 

I still don't have a formal answer why Cocoa behaves this way, but in practical use it seems to be convenient. I have defined an NSWindowController subclass with the following -init method and it works like a charm.

- (id)init;
{
    if ((self = [super initWithWindowNibName:@"MumbleMumbleSheet"]) != nil) {
        …
    }
    return self;
}

If -initWithCoder: were being called I would have to figure out how to fulfill the implicit obligation to call the super -initWithCoder: method and still get the right -windowNibName used for loading. It's much more straightforward this way.

I would still appreciate a pointer to some documentation that says this class is different and explains why and how… But in the absence of documentation there is empirical evidence.

Kaelin Colclasure
A: 

The coder methods are used for classes that have been serialised and saved to file.

What you are doing here is different. You are building your controller class into your executable. This means that there's no need to read the class itself from file as it's a part of the running application binary.

When using this controller class you need provide an init method where you provide the nib file name. Why? Well, you have the compiled class as a part of your exe but no knowledge about what the nib file is. This is how you provide that knowledge.

Think of it this way. You controller class is a part of the exe. Some link between it and the nib file needs to be made. One way would be to scan through all the nib files looking for references to this controller. That would be inefficient. Provide the name in the init and everything bootstraps.

In other words you have learnt some important lessons from your experiments. Well done, on being so observive.

No one in particular
I should have made it more clear: I *am* loading this instance of my NSWindowController subclass from a nib (well, xib now). It would be nice if we could include images here as that would make describing exactly what's where much easier…
Kaelin Colclasure
+1  A: 

I'm assuming that to instantiate your window controller in Interface Builder, you dragged a generic NSObject instance to the nib file, then assigned your custom NSWindowController subclass as the object's class, is that correct? If so, then I think they key difference going on here is that you're dealing with instantiating a generic object rather than a custom object included in one of IB's palettes.

Most of the time, when you create and configure an object using IB, the settings that you specify in the various inspectors gets encoded using the encodeWithCoder: method when the nib file gets saved. When you then load that nib file in your application, those objects get initialized using the initWithCoder: method.

However, in the case of that generic object instance, Interface Builder doesn't necessarily know anything about the class of the object being instantiated. Since you can specify any class name at all to be instantiated, if you specify a class that IB doesn't have loaded via a palette or framework, there's no way it can serialize that object using NSCoding. So I believe that when you instantiate a generic object like that, it gets initialized using init rather than initWithCoder: because it wasn't saved using encodeWithCoder: in the first place when the nib file was saved.

I don't know if this is documented anywhere, but I think that's why you're seeing a difference there. I also don't think it's specific to NSWindowController, but rather you'd see the same behavior from any object instantiated as a generic NSObject in IB, regardless of the specific class.

Brian Webster
I did do almost what you described… excepting only that I used the class browser in IB and dragged an instance of my NSWindowController subclass into the top-level of my nib. This behavior makes sense as you've described it and it seems like a useful feature. Too bad it's not better documented!
Kaelin Colclasure