Among other crazy things, Cocoa programming is mostly done in Objective C, which is a lightweight extension of C that makes it a loosely typed, object-oriented language. That, combined with a powerful set of NeXTStep support libraries, makes it almost feel like a higher-level scripting language. Hillegass devotes about 40 pages to a crash course in ObjC, aimed at intermediate or better programmers who've done the whole OO thing already in some other language (e.g. Java, C++). I have a few nits about it, but granted the book isn't about ObjC, it's about Cocoa, and eventually most of my burning questions during the chapter were answered, if not as early as they could have been.
It seems to me if you've done Java, then the concepts of classes, interfaces, instance variables, and static and instance methods translate over directly. That and if you've done C in the past, then you're pretty much set as far as pointers, addresses, etc. go. The only really screwy thing with it is its approach to memory management: the programmer manages reference counts, you call retain and release methods on objects, and to top it off some objects are autoreleased for you. Seems very powerful, if you can get your head around it. [Update May 1st, 2008: ObjC has garbage collection now]. Oh... and one more thing, the syntactical screwiness. The whole language looks really nutty; the author mentions that it was originally implemented as a C preprocessor, which totally makes sense when you look at it--funny '@', '-', and '[]' symbols everywhere, and other things which are (were?) clearly macros. This isn't C anymore.
So I thought I'd share my HelloWorld program. How exciting. Pretty much the typical "Hello, world", if not quite as ultra trivial, with a simple HelloWorld class that I think demonstrates some of the syntactical and memory management nuttiness involved here.
First the class declaration, HelloWorld.h:
#import <Foundation/Foundation.h>
@interface HelloWorld : NSObject {
// no instance variables
}
// methods
- (void)sayHello;
@end
Read that @interface line like "Class HelloWorld inherits from NSObject". Instance
variables go inside the curly brackets, methods underneath. The bizarre leading '-'
indicates sayHello() is an instance, not a static ('+'), method. Then the implementation,
HelloWorld.m:
#import "HelloWorld.h"
@implementation HelloWorld
- (void)sayHello
{
NSLog(@"Hello, world, at %@", [NSCalendarDate calendarDate]);
}
@end
We're using stuff from the NeXTStep libraries here, NSLog is like a printf() (printf()
would have worked fine, but Hillegass is teaching us the NS stuff). %@ is cool, it calls
the object's description() method and substitutes the results (i.e. toString()). More on
the square bracket stuff next. Then the main program to drive it, main.m:
#import <Foundation/Foundation.h>
#import "HelloWorld.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// my stuff
HelloWorld *hw = [[HelloWorld alloc] init];
[hw autorelease];
[hw sayHello];
[pool release];
return 0;
}
Java guys, read the "[HelloWorld alloc]" syntax as HelloWorld.alloc(), or actually as new
HelloWorld(). Note alloc() is a static method in this case. [Added May 1st, 2008: As
Aaron (Hillegass?) points out in the comments below, it's important to call init() on the
object in addition to alloc() so proper initialization happens, instead of simply
allocating the memory for it. It's surprising my program didn't crash.] [hw
sayHello] calls the sayHello() method.
So here's my take on the memory management bit. ObjC has no garbage collection, so we're back to the days of fooling around with this stuff (argh, haven't we learned anything? Anyways...) Objects maintain a reference count which the developer can manipulate by calling the retain() or release() methods. Objects destroy themselves when their reference count hits zero. This way shared objects exist for as long as they need to exist, and go away when no one wants them anymore. Slick. When you alloc() an object, it's reference count is set to 1. At the end of main() I could have called [hw release] to destroy it, or in this case, I chose to take advantage of the NSAutoreleasePool convention, which is this collection bin for holding objects to be released later, at a time of the programmer's choosing--specifically, you can see at the end of the main() method ([pool release]). By calling [hw autorelease], the hw object told whatever pool object in scope to reference it (incrementing its ref count), then decremented its reference count (well, I'm sure internally they optimize this to not do anything, since it's a wash, but that's the idea). This way my memory management (creation/deletion) is handled all in one spot--I've created it, and I've effectively freed it, but should someone else want it before I'm done with this method they can have it. This "delayed destruction" approach seems pretty clever, and has a more few more practical applications which are not really demonstrated by my simple Hello World program.
(Update Mar 3 and 20th, 2009): To compile and run all this, use a Terminal and gcc (thanks Mina and Ade!):
$ gcc main.m HelloWorld.m -framework Foundation -o hello $ ./hello 2009-03-20 11:39:06.444 hello[78751:10b] Hello, world, at 2009-03-20 11:39:06 -0700
At the top of the article I said "Cocoa programming is mostly done in Objective C" deliberately to bring up that Apple actually provides all the Cocoa/NeXTStep APIs in Java, so if you wanted, you could write (very non-portable) Java code to create Cocoa apps. It seems to me it must be a lot of work to keep both languages up to date with any API changes. (Update Mar 3 2009: and indeed, this "Java bridge" API is deprecated as of Mac OS 10.4, so never mind). However, while this may seem exciting to the ObjC-adverse, Hillegass points out that "almost no one is developing Cocoa apps in Java", mainly citing performance, but also pointing out potential bugginess and how Java just isn't the right tool for the job. Too bad! (Update Mar 3, 2009: five years later and my how my perspectives have changed--I'd pick ObjC in a heartbeat over Java).