Friday, August 15, 2008

NSApplication and delegate

Last night, I finally restarted my Cocoa learning effort, by looking at how I could write an application without using Interface Builder. IB is so vastly used that there isn't as much details available on the web on how to go about with it, nevertheless, there is enough to get started. And in fact, it is relatively easy, at first.

A Cocoa application, in its simplest expression, is composed of a single NSApplication object and one (or more) NSWindow object(s). Overall, it doesn't take much boiler code to get something going, which is good:
int main(int argc, char *argv[])
{
NSWindow *lWindow;
// create an auto-release pool
NSAutoreleasePool *lPool = [[NSAutoreleasePool alloc] init];

// initializes the display environment and connects to the window server
// and display server
[NSApplication sharedApplication];

// create a window
lWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(10,10,320,240)
styleMask:kStyle
backing:NSBackingStoreBuffered
defer:NO];
// set the window's title
[lWindow setTitle:@"Hello world!"];
// show the window and move it foreground
[lWindow makeKeyAndOrderFront:nil];

// start the application run loop
[NSApp run];

// release the window
[lWindow release];

// release the pool
[lPool release];
}

The Application object gets a bunch of notification from the system during its life-time. If I wanted to perform some actions in some of them, there is two ways of doing it: I could subclass NSApplication and implement the corresponding methods, which is the usual way of doing it in 99% of the toolkits out there ... or, I could follow the Cocoa way and use a delegate instead. Since the later is what Apple encourage developers to do, the NSApplication class is built to support the addition of a delegate by sending it a setDelegate message.

Now, as expected, this message take as single argument: the object to be the delegate. So far so good. However, instead of defining the argument with a specific class, for example something like said NSApplicationDelegate, it is defined as an id (meaning any kind of object). Since I'm still more of a C++ kind of guy than an Objective-C dude, I found myself a little puzzled by this but still decide to move forward by searching in NSApplication.h (since I didn't see anything in the class documentation) for the delegate class I am expecting to have to subclass, or some sort of protocol definition.

In the header file, I was nicely surprised to see that NSApplicationDelegate does exists, but in a way I was not expecting, at all: @interface NSObject(NSApplicationDelegate). Yep, that's right. A category ... meaning that any object with NSObject for root parent, can be the application delegate ... Since 99% of all Cocoa's classes have NSObject as root, any objects can be the delegate .... including widgets! If this isn't yucky, I don't know what is! Why on earth didn't they use a protocol!??

1 comment:

Anonymous said...

Delegates haven't historically conformed to any protocols in Cocoa (or Yellow Box, or OpenStep) because delegates have both required and optional methods, but until Mac OS X 10.5 protocols only supported required methods.

Check out NSTableView's delegate and data source to see just why this is important. There are a few dozen methods...

Objective-C 2.0 introduces optional protocol methods, so any delegation you set up in your own apps and frameworks can use protocols.