ed Objective-C. This ha
s become a source of angst for Macintosh C++ developers who must learn a new programming language.
This article offers a gentle introduction to Objective-C that C++ programmers can easily understand. It assumes familiarity with common OO concepts, such as class, inheritance, and method (known as
member function
in C++).
Objective-C is not as large and complex as C++, yet it's fully OO and supports inheritance, encapsulation, and polymorphism. Like C++, Objective-C is a "hybrid" language; in other words, it's an ANSI C superset that supports standard C scalar types, such as
int
, in addition to object types, such as
NSArray
.
Objective-C's run-time system allows for the creation of dynamic, extensible programs. The run-time facilitates the building of bundles, which consist of one or more compiled classes that can be dynamically loaded or linked into a running program. The language's dynamic typing and binding go hand-in-hand with dynamic loading. Ob
jective-C allows instance-variable objects to be a generic type, id, which means the variable's class is not known until the program is running (i.e., the variable's class is not fixed at compile time). Once an object has been typed, the run-time automatically binds the appropriate class methods to the instance while the program is running.
The Class Interface
By convention, the source code for an Objective-C class is divided into a public interface and a private implementation. The public-interface declarations can be found in an appropriately named file suffixed with
.h
. Here I'll investigate the structure of an interface file by declaring a simple class called Pet. The listing
"Pet-Class Interface (Pet.h)"
contains the public interface for this class.
A colon separates the class name from the superclass name. In this case,
Pet
's superclass is
NSObject
-- the root class -- which is declared in the Foundation Kit.
NSObject
is the only class without a superclass. (Apple prefixes Rhapsody class names with
NS
to prevent namespace collisions with classes.)
In C++, an object is simply a glorified structure. In Objective-C, each object is a pointer to a structure. This distinction is important when declaring instance variables, as you'll see below.
The first declared variable is the pet's
name
. This variable's type is statically declared as
NSString
, which is a Foundation Kit object that encapsulates a Unicode-compliant string. Remember that objects are pointers to structures, so the asterisk is required in front of
name
. If you didn't know
name
's class type at compile time, you could dynamically type it to
id
, but you would lose some compile-time error checking. The second instance variable,
age
, is declared in standard ANSI C fashion.
Declaring Methods
In almost every OO language, methods come in two flavors: instance methods and
class methods. In this regard, Objective-C follows the same conventions as C++. But Objective-C methods can override any inherited method. In C++ jargon, it can be said that all Objective-C member functions are "virtual."
A method's return type and its argument types can be ANSI C scalars or Objective-C objects. Arguments and return values that are objects can be statically declared (e.g.,
NSArray
) or dynamically declared (e.g.,
id
). Unlike ANSI C, Objective-C's default type is
id
, not
int
.
When you write interface declarations, instance methods are preceded with a minus sign, and class methods are preceded by a plus sign. (It so happens that the
Pet
class consists only of instance methods.) Each method name is separated into one or more key words, each suffixed with a colon to separate it from the argument name. The colons are considered part of the method's unique name.
The class-implementation file is shown in the listing
"Pet
-Class Implementation (Pet.m)"
. This is where the Objective-C methods are defined for your class. Note how the instance methods provide external access to the
name
and
age
instance variables. Rhapsody uses this convention extensively; almost every publicly accessible instance variable should have a set method (e.g.,
setAge:
) and a get method (e.g.,
age
).
Structurally, Objective-C methods are defined similarly to ANSI C functions. When defining a method, you first state the method name (from the interface) and then follow it with a code block that contains the algorithms you want to perform. The code block looks just like a C function block with one important difference: You can mix Objective-C messages with regular ANSI C code.
Using Messages
Defining classes, creating instances, and sending messages are the essence of object-oriented programming (OOP). Once you define a class, you need to send messages to objects. Below are a couple of sa
mple message expressions.
[myDog setName:@"Rover"];
[myDog setAge:3];
Here you're using the class methods
setName
and
setAge
in actual message expressions. Square brackets must be placed around the receiver and the message. The message's receiver is an instance of the
Pet
class (note how the receiver is always placed before the message). The message arguments are an
NSString
instance (the unusual @" construct begins a literal
NSString
containing "Rover") and a literal integer (3).
You can put an Objective-C message expression anywhere you'd put an ANSI C function call. Objective-C also allows you to nest messages. When nesting, the return value for the innermost message expression is used as the receiver for the next expression, and so on.
The listing
"A Simple Objective-C Program (PetTest.m)"
is basically an ANSI C
main()
function that contains some Objective-C messages. Since the program uses O
bjective-C, you suffix the filename with
.m
rather than with
.c
.
The first line of code,
myDog = [[Pet alloc] init];
warrants further explanation. This is an example of a nested message expression. Whenever you create a new Objective-C object, you must first allocate memory for its instance variables and then initialize the object. By convention, rather than doing this on two separate lines, you ask the
Pet
class to allocate space for a new instance and then initialize the allocated instance -- all in one line of code.
Since the
Pet
class inherits the methods
alloc
and
init
from
NSObject
, it already has the necessary machinery to create instances of itself. The return value from the outermost expression is a new
Pet
instance, which is assigned to the
myDog
local variable. The last line in the program uses a standard
printf()
function to display the contents of
myDog
.
The World of Objective-C
Objective-C is a simple language that's easy to learn and use. C++ programmers who have already switched to Objective-C often rave about the clear syntax and vast flexibility that it provides. Although Java is more flexible than C++, it still retains C++'s obscure messaging syntax, and most developers agree that Java is just not ready for the creation of industrial-strength applications.
You can obtain further information about Objective-C development from Apple's developer site (
http://devworld.apple.com
), from Next Computer's Web site (
http://www.next.com
), and from Metrower
ks' Web site (
http://www.metrowerks.com
).