Objective-C Programming/syntax

Objective-C is an object-oriented programming language, and is a layer over the C programming language. This means that if you know how to write C, there are only a few syntax changes to learn.

In this section, we will look at how we can implement classes and instantiate objects in Objective-C. If you are unfamiliar with object-oriented programming, see Objective-C concepts.

Basic syntax edit

If you have studied C, you can skip this section and proceed to the next section, A word on runtimes. If not, or if you're a little rusty, read on.

In C, code is contained within a function. Functions are composed of several statements, each of which are terminated by a semicolon. For example, a simple function in C to add two numbers may look like this:

int add (int a, int b)
{
    int c;
    c = a + b;
    return c;
}

This sample has the following lines:

  1. The function definition (which returns an int (integer), is named add, and takes two parameters, both of which are integers). // Integers are whole numbers like 6, 66 or 567 and not numbers with decimal places like 5.6.
  2. The opening function brace
  3. A variable declaration
  4. An assignment statement
  5. A return statement, which returns the value of c to the calling function/
  6. The closing function brace

For control flow, C and Objective-C use:

  1. for (<initial>;<condition>;<increment>)
  2. while (<condition>)
  3. do ... while (<condition>)
  4. switch (<condition>)
  5. if (<condition>) then {<statements>} [else <statements>]

The for, while, and do statements will continue execution of a loop until the condition is false. The switch and if statements jump to different statements depending on the condition.

Objective-C does not implement or import any functions by default. Instead, they need to be imported by using the #import preprocessor directive. (#include works too, but generally it is not used in Objective-C - #import works better because it won't import the same thing twice like #include can try to do)

A word on runtimes edit

Objective-C requires what is known as a runtime system to provide you with Objective-C features. The runtime takes care of the creation, management, and destruction of objects.

If you have the gcc compiler, you should have the Objective-C runtime already installed. Otherwise, you may have to install the runtime separately. Note that gcc is a compiler collection; the full install contains not only the C compiler, but also C++, Java, Objective-C and even Fortran-95 and Ada 2005 compilers. However, it is possible to install gcc only partially, for example only the C compiler. Therefore, the Objective-C runtime may or may not be installed with gcc. Check your distribution.

Two main systems are used to run Objective-C programs:

  • the GNU runtime, which is provided as a part of gcc on Unix and Unix-like operating systems;
  • the NeXT runtime, which is provided on NeXTSTEP, OPENSTEP, and Mac OS X operating systems.

This text assumes you are using the GNU runtime, but the two runtime systems are almost identical.

This text does not cover the OPENSTEP, Cocoa, or GNUstep frameworks, but the skills learned here will be helpful when developing with those systems.

Writing classes in Objective-C edit

Writing an Objective-C class requires a few design decisions before we start writing any code. Say we are writing a class to represent a point called Point in a two-dimensional plane.

We need to ask ourselves two questions:

  1. What data do we need to store and use? This relates to the instance variables we need to declare.
  2. What operations do we need to perform? This relates to the methods we need to define.


For this example, we'll use double variables for the x and y coordinates. We'll define a method to get both coordinates, and we'll define a method to get their distance from the origin.

The interface edit

#import <objc/Object.h>

@interface Point : Object
{
@private
   double x;
   double y;
}

- (id) x: (double) x_value;
- (double) x;
- (id) y: (double) y_value;
- (double) y;
- (double) magnitude;
@end

Let's examine what each element of this interface means.

#import <objc/Object.h>
 
@interface Point : Object

The @interface line says that we begin the declaration of the Point interface. We inherit from another class called Object. Objective-C provides you with a generic class, called Object. The Object class is a root class -- it does not inherit from another class. The Object class provides a set of methods that provide key functionality for an object to be used and recognized by the Objective-C runtime. As in C, we need to include Object's header file, Object.h, before we can use the set of methods declared in the header.

If you don't explicitly inherit from some class, your class becomes a root class. (In Objective-C, there can be many root classes.) That's probably not what you want to do, because creating a root class is a very tricky and advanced topic that is only useful in very specific situations. In most cases, you will want to inherit from Object or some class that inherits from Object, etc. If you develop in NeXTStep / GNUstep / Cocoa, you will mostly be using another root class called NSObject, which provides different basic methods than Object.

The word import means that we only include the file once. This solves problems like recursive includes.

{
@private
   double x;
   double y;
}

Anything between the braces in an interface declaration specifies the instance variables that the class has.

The @private line is a visibility modifier: it says that the instance variables after it are private, i.e. they are accessible only from the class that declares them. It is good practice to mark all your instance variables private: they contain the state of an object and they should never be changed except by the object itself.

- (id) x: (double) x_value;

The declarations for the methods come after the instance variables. This is a declaration for the method to set the x value. It's common Objective-C style to name the setter method with the same name as the variable it's setting.

The hyphen specifies an instance method (we'll look at these later). Then comes the name for the method (this method is called x: - note the colon), and the colon signifies an argument, called x_value, and is of type double.

The cast on the x_value argument is necessary, because unlike C, the default type is id, and not int. The type id is very special—it is a type that can hold any object whatsoever. The first cast is not strictly necessary, but should be used for clarity. The first cast tells us that the method x returns an object back.

- (double) x;

This is another method named x (no colon), but it returns a double. This is the specification for the method that gets the value of the x variable. There is no conflict with the previous method because the types are different, and the previous method takes one argument whilst this takes none.

@end

After all the methods and instance variables are specified, this symbol marks the end of the declaration.

The interface specification goes in a .h file—a header file. It's customary to call the file after the class, so we would create a file called Point.h.

The implementation edit

#import "Point.h"
#import <math.h>

@implementation Point

- (id) x: (double) x_value
{
   x = x_value;
   return self;
}

- (double) x
{
   return x;
}

- (id) y: (double) y_value
{
   y = y_value;
   return self;
}

- (double) y
{
   return y;
}

- (double) magnitude
{
   return sqrt(x*x+y*y);
}

@end

This is the implementation for the Point class. We implement the methods in the interface defined above. Let's have a look at each element of the implementation in turn.

#import "Point.h"

Again, we import Point's interface, just as we do in C.

@implementation Point

This is a marker that identifies the beginning of the implementation.

- (id) x: (double) x_value
{
   x = x_value;
   return self;
}

This is a typical method implementation. We can use the x variable directly without having to declare it since it is already declared in the interface, and is accessible only to the methods of this class. The behaviour, in general, is like an ordinary C function. Here we assign the value of the argument x_value to the instance variable x.

The function then, returns the entire, current object as modified. The keyword self represents the current object.

- (double) x
{
   return x;
}

Here is the simple method to get the value of the x variable. We simply return it.


The behaviour for the other methods should be similar to those above. The @end keyword ends the implementation.

The implementation specification goes in a .m file. It's customary to call the file after the class, so we would create a file called Point.m.

Using the objects edit

Since Objective-C comes from C, we write a main function to make use of the class that we just created. Here's one typical main function.

#import "Point.h"
#import <math.h>
#import <stdio.h>

int main(void)
{
   Point *point = [Point new];
   [point x:10.0];
   [point y:12.0];
   printf("The distance from the point (%g, %g) to the origin is %g.\n",
      [point x], [point y], [point magnitude]);
    
   return 0;
}

Let's examine what happens here.

#import "Point.h"
#import <stdio.h>

We import the interface to Point so we can use it. We import stdio.h so we can use printf.

    Point *point = [Point new];

This is a typical Objective-C method call:

  • Point *point declares, technically, a pointer to an instance of type Point. Actually, it may be best to think of this merely as a variable holding a Point object, but keep the pointer idea in mind.
  • [Point new] calls a method called new. The first half before the space represents the object we call the method on. The second half is the method name and arguments. The new method is called a class method, because it doesn't do something with respect to an instance of a class, it does something with respect to the class itself. The new method allocates memory and initializes the object, making it ready for use. There is no need to explicitly delete an object, as Objective-C keeps track of the number of references to a given object, and deallocates them as necessary.
    NOTE: The new method is shorthand for alloc and init and may not always be available. If it is not, the object can be initialized and made ready for use in the following fashion: [[Point alloc] init]
    [point x:10.0];
    [point y:12.0];

These are some typical instance method calls. We call point's method x: and y:. In Objective-C terminology, we say that we send point a message to apply to the method x:.

These messages assign point's x and y variables. Recall that the x: and y: methods had in them return self;. This means that we can chain the two messages together, as follows:

[[point x:10.0] y:12.0];

The message [point x:10.0] returns an object, point, with its x variable set. Then on that object, the outer message assigns its y variable.

    printf("The distance from the point (%g, %g) to the origin is %g.\n",
       [point x], [point y], [point magnitude]);

The printf statement has in it the method calls [point x], which returns the value of the x variable for printing, [point y], which does the same for the y variable for printing, and [point magnitude] which calculates the distance and returns that value.


The Objective-C programming language: Objective-C concepts - Objective-C syntax - Objective-C in depth - Objective-C advanced features