views:

303

answers:

1

I'm having a problem with my Cocoa app. I'm using my app delegate as a controller, and opening one window in a NIB file. Clicking a toolbar button opens another window from another NIB. Clicking save on this second window calls a method on the app delegate/controller. All this works fine.

The strange thing is that I can't figure out is that the app delegate points to one memory location when I click the toolbar button and to a different memory location after clicking save on the second window. It's as if a second app delegate/controller is being created, though stepping through the code doesn't give me any indication of that occurring.

Is there a better way to architect this type of application? Any idea of where I'm going wrong?

+1  A: 

It sounds like you're creating a second instance of your AppController class in your window's nib file. You can't do that, each instance of an object in a nib file will be instantiated when a nib is unarchived at runtime. This means if you have an AppController instance in MainMenu.xib and also one your MyWindow.xib file, the AppController object will be alloced and initialized twice.

Normally the way you'd handle this is by using the responder chain. In your Window nib, you assign First Responder as the target of your actions. This means that when the action method is called, the app will ask the currently focused view/control (the one that has first responder status) if it responds to the method by calling the -respondsToSelector: method and passing in the action selector.

If the first responder doesn't respond to the method, the message travels up the responder chain until an object that does respond to the method is found. If no object responds to the method, the NSApplication instance handles it and calls NSBeep().

Just before the method is sent to the NSApplication instance, the application delegate is asked if it responds to the selection. In this case, if your AppController object is set as the application delegate, it will receive the message sent as the action from your object in the window nib.

If this isn't clear enough, it's worth reading the Event Handling guide

You don't have to use the responder chain. You can call a method on the application delegate by calling [[NSApp delegate] yourMethod]. You could also store a reference to the app controller by adding it as an instance variable to your NSWindowController object that loads the nib and setting it at creation time, like so:

- (id)initWithAppController:(id)aController
{
    self=[super initWithWindowNibName:@"YourWindowNibName"];
    if(self)
    {
        appController = [aController retain];
    }
    return self;
}

Your window controller can then call methods of your AppController directly.

Rob Keniger
Indeed this is what I was doing. I will take some time reading the recommended guide; I don't quite get how to work with the FirstResponder object and its connections to my code. Thanks.
Shawn