Objective-C is a programming language. It is the predominant language used for writing end-user graphical software for computers running the Mac OS X operating system, and is effectively mandatory for writing commercial software for the iPhone.

Objective-C is a superset of the C language. In other words, it has all of the semantics and other features of C, as well as various additions, including:

  • objects
  • classes, which are themselves objects
  • single-inheritance subclassing
  • optional dynamic typing (for objects) using the generic type "id"
  • dynamic messaging
  • protocols, a means of declaring a collection of messages which will be implemented later
  • categories, another means of declaring a collection of messages which can optionally be implemented immediately or later, allowing arbitrary extension of the behaviour of existing classes without having to subclass
  • object and class introspection/reflection

 

The fundamental construct which distinguishes Objective-C and its use is the dynamic message. A dynamic message is one in which the message name, the receiver, and the arguments can all be varied at runtime. Moreover, messages can be archived as objects which can be transmitted over a network (using the Distributed Objects system) or recorded to disk (though there is no built-in facility for this in Mac OS X or the iPhone OS—it's not hard to do it in a custom manner, however).

To enable the dynamic messaging features of Objective-C requires a support library, the obj-c runtime. The library includes a collection of structures and functions which allow the dynamic creation and inspection of classes, including the ability to add or replace methods at runtime, and, most importantly, the ability to associate functions with method selectors and to invoke method implementations in response to the sending of messages.

Most programmers writing Mac or iPhone applications will use the features of the runtime indirectly. The vast majority of classes are written and created at compile time, and most objects are instantiated from classes which reside in the various Objective-C frameworks (a kind of dynamic library) included in Mac OS X, such as AppKit, Foundation, Core Data, Calendar, and more. (Many of the same frameworks also appear on the iPhone, with the key exception of AppKit, which has been replaced with UIKit, which is more streamlined and specially designed for use with the smaller, multi-touch-enabled screen).

The most distinct feature of programming in Objective-C is the use of the messaging syntax, for example:

int foo = [array count];

which will return an integer with the number of objects in an object of type NSArray. the "count" is the message selector, which is like the name of the message. A message is more than a name; it also includes a receiver and arguments, if any.

Here is an example of a message send statement containing an argument:

id obj = [array objectAtIndex:0];

A key distinction in the terminology of Objective-C is the message as opposed to the method. Messages are sent, while methods are invoked when a message is received. It is entirely possible to send a message to an object which does not understand it (i.e., which does not implement a method corresponding to the message selector). In that case, the runtime will instead invoke a default method (described later).

It is improper (though common) to misuse the term "call" when describing the invocation of methods. Functions, defined using the same language syntax as in ANSI C, are called. Methods are invoked. However, a method is implemented as a normal C function: when a it is invoked, the underlying function is executed in the same way as a normal function—it is called by the runtime (specifically, by the objc_msgSend function, often the most called function in an Objective-C program). But to acquire a good natural sense of how Objective-C programs behave, it is always good to remember that Objective-C code sends messages, and those messages are received—indirectly—via the runtime, and the results are only defined at runtime.

Messages can be sent to normal objects (instances of classes), or to classes themselves (which are also called class objects, or factory objects). When defining a class, if the class object itself responds to a message, the method is declared prefixed with a "+" character, similar to this example:

+ (id)alloc;

whereas a method intended for instances of the class start with a "-" character:

- (id)init;

Between the +/- and the selector is the return type. The default return type is id (I say "id" like the Freudian subconscious, but it's probably more correct to say "eye-dee"; I didn't learn from greybeards, but from the Apple ]documentation] on the Internet). Thus the return type is optional, although it's nowadays considered bad form to write it like this:

-init;

In order to send a message to a class, you either use the class name explicitly, or you can define a variable of type "Class", and set that variable by sending the -class message to any object (regular instance or class object).

A method which takes an argument is declared like this:

- (id)objectAtIndex:(int)idx;

The colon defines an argument. Multiple colons mean multiple arguments, one per colon. Here are two declarations for methods taking multiple arguments:

- (void)initWithObject:(id)obj forKey:(id)key;
- doSomething:arg1 :arg2;

The first form follows the customary—though verbose—technique of prefixing the colon with descriptive text. Text ending with a colon is called a keyword. After each keyword is an argument, including an optional type (default is, again, id). The second example eschews the text in the second keyword, as well as the return and argument types. The name of an argument is mandatory.

Messages can be nested to make more concise statements. The most common nesting is see in object creation. The customary way to create an object is to send a class the +alloc method, which returns an instance, which can be sent the -init method, as follows:

id myWindow = [[NSWindow alloc] init];

This gives you a window object, at which point, you could make it appear onscreen, as follows:

[myWindow makeKeyAndOrderFront:nil];

"nil" is like NULL -- it is the zero pointer, but of object type. The message -makeKeyAndOrderFront: is an example of an action message. Many classes in the AppKit framework are subclasses of NSResponder. NSResponder is an abstract class which defines common behaviours of views, controls, windows and other objects which respond to user interface actions like key presses and mouse events.

When you are done with your window, you should free it from memory (unless you have enabled automatic garbage collection), by sending it a -release message, like so:

[myWindow release];

Now, your window object is gone. Don't send it any more messages, or you will probably crash your program. Cocoa, as Apple calls their Objective-C development environment, only added support for automatic memory management (garbage collection) in Mac OS X 10.5 (Leopard), and it is optional. It only works for Objective-C objects, not C structures and not Core Foundation types; the former you must still allocate with malloc() or a similar function (if you want them to live beyond the current stack frame), and the latter you create and destroy with Core Foundation functions.

For more information, check out Apple's Mac OS X developer library, including: Objective-C: a Primary and Object-Oriented Programming with Objective-C.

I almost forgot: what happens when you send a message to an object which does not implement the corresponding method (i.e. that has no member function which is bound the the selector for that message)? The runtime invokes -doesNotUnderstandSelector:, which is a method defined on the root class, NSObject (and which throws an exception). However, you can override -doesNotUnderstandSelector: in your custom subclass to do whatever you want, including sending the message to a completely different object.