Cocoa and GNUstep are both the offspring of OpenStep, which is in turn the offspring of NeXTStep which is the software platform NeXT Computer Inc. decided to develop for their hardware in the 80's. Of the two, Cocoa is the most complete in terms of frameworks, documentation and development software and I write about Cocoa here because I am more familiar with it and because it is closer to what GNUstep should (will) be than GNUstep is, though a lot of this will apply anyway.
Both Cocoa and GNUstep are object oriented programming environments comprising of an integrated editor/compiler/interface builder and a set of frameworks (dynamically linked libraries) which store almost all of the typical objects (and their methods) you might want in an application. As well as Objective-C, Cocoa programs can also be written in Java, even AppleScript, perl or python and there is no reason why more languages should not be added.
Objective-C is a thin layer on top of C in the mold of Smalltalk, the only syntactic change to C is the addition of messages in the form
which sends the message "method" to "object" or if you prefer, means
object->method(). Arguments are separated by colons ":" so
tells the object; "method with argument1 and argument2" or means
[object method:argument1 :argument2]
object->method(argument1, argument2). Objective-C is dynamically typed (unlike staticly typed C++ and Java), which means you can send messages to objects that don't know how to receive them, in Cocoa that means that the message gets passed along the receiver chain until it meets an object that does, which is handy if you don't know exactly where it will be used when you write the code. Dynamic typing and genuine message forwarding also mean that objects can be distributed across applications and even across networks and still be accessed with the same simple [object method]. Dynamic loading means that Obj-C programs can even load plugins and code on the fly at runtime.
The basis of Object Oriented Programming is of course 'objects' and you may recall that reusability and inheritance are among the benefits OOP offers, in Objective-C objects generally inherit or are descended from a root object and in Cocoa the root object is called NSObject (a name which Cocoa itself inherits from 'NeXTStep'). This simple inheritance means that all Cocoa objects being decendents of NSObject inherit some standard functionality (like conforming to Cocoa's memory management scheme and dealing with message forwarding). Below NSObject in the Cocoa framework there is a tree-like structure of inheritance which contains such things as data containers, GUI elements and application services, each object inherits methods, variables and functionality from its' super and adds to them.
Thanks to Objective-C's flexibility all objects can be classed as being of the type of one one of their ancestors, so both NSButton and NSSlider can be passed as NSControl, useful if you don't know what kind of control you'll be listening for when you write the code. Taking this to the extreme, all objects can be passed as type 'id' - the type of NSObject. This makes sense if you don't know what kind of object you'll be dealing with (perhaps because you are communicating with an application across a network or because you are loading code at run time) because once you have the object or a reference to it you can ask it where it comes from and what methods it responds to and then deal with it accordingly. Sweet.
In Cocoa and GNUstep objects are accessed through a clear and well thought out API which manages to cover just about every circumstance, meaning that applications get a huge amount of functionality for free and making Cocoa/GNUstep a particularly lucid way to program as much of the code is behind the scenes. In Objective-C, a not untypical line of Cocoa code looks like this:
Which tells the object "window" to do the method "close". As it happens
window is an instance of NSWindow, which means that it responds to the
close message automatically without any coding by the applications developer. Of course, that line of code has to be inside a method of an object for it to be called, so in context:
- - (IBAction)CancelButtonClicked:(id)sender
- [window close];
Yes really, look again:
- - (IBAction)OKButtonClicked:(id)sender
- float intensity = [intensitySlider floatValue];
- [window close];
- cpImageData = [self swirlImage:cpImageData size:cpImageSize intensity:intensity];
That's three lines of instructions for the program to go through when the user clicks the OK button. Of the three methods used, (
swirlImage:size:intensity:) only the last one is not built in to Cocoa and actually needs writing. If you need some functionality that isn't built in already (and you will eventually) you can just subclass whichever object is closest to what you want and add or override whatever functions or variables you want different.
So for instance the class that the above
OKButtonClicked: are contained in might be a subclass of NSWindowController which would just mean having a header file like:
- #import <Cocoa/Cocoa.h>
- @interface CPImageFilter: NSWindowController //<---
- IBOutlet id intensitySlider;
- UInt8 *cpImageData;
- NSSize cpImageSize;
- - (IBAction)OKButtonClicked:(id)sender;
- - (IBAction)CancelButtonClicked:(id)sender;
- - (UInt8 *)swirlImage:(UInt8 *)data size:(NSSize)size intensity:(float)intensity;
- - (UInt8 *)filterImage:(UInt8 *)data size:(NSSize)size;
and an @implementation file which contains the implementations of the methods like like the one you saw above for OKButtonClicked:. Luckily you don't have to remember the exact structures of these files because the development tools will create outlines for you and Interface Builder will even add the actions and outlets.
Other GUI objects supplied include buttons, sliders, [text/ image /movie /OpenGL /...]Views, toolbars, and menus amongst many others and they can all be implemented and hooked up with your code using drag and drop operations in the integrated Interface Builder application which even draws guides to make sure everything is aligned right. Like Swing, Cocoa programming is event triggered but creating handlers is often code free, just a case of just drawing connections in Interface Builder. Of course if you want dynamic interfaces you can still code or part code them by subclassing the GUI element in question.
Because interface elements are just instantiated descendants of NSObject with some values set (like position, state, color etc) they are not stored in some mangled format but "frozen" as objects by Interface Builder and then dynamically loaded at runtime when needed.
The data structures Cocoa offers include arrays, dictionaries, which store key value pairs, strings, which have a huge variety of methods for creating, comparing, appending, and taking from each other, sets, which can be unioned and intersected and objectified byte data and all of those also come in mutable forms (which can be extended, reduced, and swapped around internally) and all are flexible enough to hold any kind of object. All of them are useful in certain circumstances but tiresome to recode for a single implementation, with Cocoa/GNUstep they're just there waiting to be used, and subclassable if need be.
Application services you get for free or minimal work include document management, undo/redo, printing, scripting, filesystem access and spell checking. If you want to you can import the web kit and build a browser into your application as easily as adding a picture. All of this makes building a fully fledged applications with all the normal functionality you expect very easy.
Memory management in Objective-C Cocoa amounts to making sure you send an
[object release] message for every
[object retain] you send or alternatively you can send an
[object autorelease] message which is essentially a way of telling the application that you are finished with it, the object will be sent to an autorelease pool and when the code reaches the end of it's run cycle, all the objects in the pool will be sent an
[object release]. Any object that reaches a retain count of 0 automatically deallocates itself - an example of reference counting garbage collection. Objects are almost universally referred to by their pointers and generally allocated into memory with something like
[object alloc] - so no worries about
The clarity of the language, the way you can build applications like Lego in Interface Builder, and the fact that many very powerful features are automated make it the perfect environment for beginners and for people who want to focus on what the program is there for rather than spending a lot of time building an interface or creating some intermediate structure that has been done many times before just a little bit different.
But doesn't throwing these behemoth catch-all objects around carry some overhead? Well, yes it's true that Cocoa apps aren't famed for being like lightning but often speed isn't an issue, when displaying a menu a few extra milliseconds don't matter - especially if you saved minutes or hours coding. When you do need speed (like during gameplay, rendering graphics, complex functions) you can change up a gear. Lower level technologies like Quartz (or CoreGraphics), OpenGL, and QuickTime which aren't as easy to use or as lucid but are faster and more powerful are easily integrated and in Objective-C (a strict superset of C) you can create the usual C arrays and structs, use regular C code and
<< to your hearts content without any overhead whatsoever.
In the case of our image filtering example this might be implemented by storing the image data in a regular C array (not an object) and making sure that inside of the loops that run through the pixels (where the operations will be called many times) are bitwise C operations and simple functions only. So
swirlImage:size:intensity might look something like this:
In short there aren't many programming environments that offer the flexibility, scalability, reusability, ease and power that this one does. Also with high level code which relies only on it's frameworks, there is no reason why one day an application written in Cocoa / GNUstep could not be simply recompiled for another platform from the same code. If you want to update one part of the framework like optimizing some functions or changing the implementation of some service then all of your programs that rely on it will be able to take advantage of the changes with rewriting. If GNUstep becomes more popular and it's frameworks are improved these are real possibilities and when that happens I'll consider a free OS.
- - (UInt8 *)swirlImage:(UInt8 *)data size:(NSSize)size intensity:(float)intensity
- unsigned int x, y, w, h, i;
- w = i = round(size.width);
- h = round(size.height);
- UInt8 *buffer = malloc(sizeof(UInt8) * w * h)
- UInt8 *ptr = buffer;
- while (h--) //loop through the rows
- while (i--) //loop through the columns
- x = someSimpleCFunction(i, h, intensity);
- y = anotherSimpleCFunction(i, h, intensity);
- *ptr++ = *(data + y * w + x);
- return buffer;