Objective-C Primer

The iPhone API uses the Objective-C language. Objective-C is an application of principles from Smalltalk to the C language. The idea was to combine the power of the C language, which is an industry standard, with the object-oriented programming approach of the Smalltalk language. The result is a language that might be confusing at first, but it makes sense once you understand a few concepts.

Editing the App ID in Info.plist

Figure 1-22. Editing the App ID in Info.plist

Setting the device as the build target

Figure 1-23. Setting the device as the build target

The first thing to know is that Objective-C is a strict superset of C. Anything that you can write in C you can compile using the Objective-C compiler. C-style structs, function calls, memory allocation, and pointers are all available. However, in addition to all of the normal C language syntax, Objective-C adds some of its own features as well, such as thread synchronization, try-catch blocks, and garbage collection. The primary improvement provided (and the reason for the language) is an object-oriented structure.

Classes

Classes in Objective-C are conceptually very similar to Java and C++ classes. A class is an object that contains data, called member variables, and functions, called methods. Just like in Java and C++, classes are usually defined before they can be used (although in Objective-C, they can also be created at runtime). You define a class using the @interface keyword. Similar to C++, Objective-C classes should be defined in an .h file, while their implementations should be separated into an .m file. Also as with C++, you may use the @public or @private keyword to denote the level of syntax protection of the following lines. Objective-C is different from C++ or Java, however, in that it defines its methods outside the curly braces of the class. The methods are associated to the previous class and terminated by an @end keyword.

The following code creates a class named Animal:

@interface Animal
{
    // Member Variables go here
@private
    int foo;
}
    // class Methods go here, outside the braces
    - (int) bar: (double) input1;
@end

Notice the interesting way methods are defined: they begin with a for normal functions (or a + for class methods, which we will discuss shortly), followed by the return type of the function in parentheses and the name of the function. If the function has parameters, each is written with a parameter description followed by a colon, the parameter type in parentheses, and the parameter name (except for the first parameter, which uses the function name instead of a parameter name).

Here is the same class in C++; note the semicolon required at the end:

class Animal
{
    // Member Variables and Methods go here
private:
    int foo;
public:
    int bar( double input1 );
};

Once more for Java:

class Animal
{
    // Member Variables and Methods go here
    private int foo;
    public int bar( double input1 ) {}
}

All three languages can use // for single-line comments.

And just as in Java and C++, classes can extend or inherit other classes. A common base class that almost all Objective-C classes inherit from is NSObject, which we will explain later. The syntax for inheritance is similar to C++, except that public and private keywords are not used in front of the parent class:

@interface Animal : NSObject
{

}
    //Objective-C inheritance
@end

class Animal : public NSObject
{
    //C++ inheritance
};

class Animal extends NSObject
{
    //Java inheritance
}

It is important to note that just like Java Objective-C cannot inherit from multiple classes. Say you want to create a class Animal that inherits NSObject, but also inherits a class GameEventListener, which allows it to respond to special events in your game. In C++, you could define GameEventListener as an abstract base class and inherit from both. However, in Java, you would have to define GameEventListener as an interface class, and in Objective-C, you would define it as @protocol. A protocol in Objective-C is similar to an abstract base class in C++, except that it must be absolutely virtual. It cannot have any member variables or method implementations. Just like interfaces in Java, a class in Objective-C may implement as many protocols as necessary.

Here is the implementation in C++:

class GameEventListener
{
    // Member Variables, Methods and Virtual Methods go here
private:
    bool active;
public:
    bool isListening(); //returns true if active is true
    virtual void handleEvent( int event ) = 0;
};

class Animal : public NSObject, public GameEventListener
{
    // Member Variables and Methods, and Override Methods go here
    // any pure virtual functions from GameEventListener must be implemented
private:
    int foo;

public:
    int bar( double input1 );
    void handleEvent( int event );
    // isListening() already implemented, no need to override
};

Here is the same implementation in Java:

interface GameEventListener
{
    // interfaces may not contain Member Variables
    // Method definitions go here, they cannot be implemented yet
    public bool isListening( );
    public void handleEvent( int event );
}

class Animal extends NSObject implements GameEventListener
{
    // Member Variables, Methods and Override Methods go here
    private int foo;
    private bool active; //must be defined here

    public int bar( double input1 ) {}
    public bool isListening( ) {}
    public void handleEvent( int event ) {}
}

The Java interface class is called a protocol class in Objective-C, so we define it using @protocol:

@protocol GameEventListener
    // protocols may not contain Member Variables, no curly braces
    // Method definitions go here, they cannot be implemented yet
    - (BOOL) isListening;
    - (void) handleEvent: (int) event;
@end

@interface Animal : NSObject <GameEventListener>
{
    // Member Variables go here
@private
    int foo;
    BOOL active;
}
    // Methods and Override Methods go here
    - (int) bar: (double) input1;
    - (BOOL) isListening;
    - (void) handleEvent: (int) event;
@end

Note

Programmers who are experienced in using template classes in C++ or generics in Java may get confused here. Although the syntax for using protocols in Objective-C looks like the syntax for templates in C++ and generics in Java, it is not the same thing.

As we mentioned earlier, function implementations are separated into .m files. The C++ implementation of the example would look like this:

bool GameEventListener::isListening()
{
    return active;
}

void Animal::bar( double input1 )
{
    //do something with input1
}

void Animal::handleEvent( int event )
{
    //do something with event
}

And the Objective-C implementation would look like this:

@implementation Animal

@synthesize foo;

- (void) bar: (double) input1
{
    //do something with input 1
}

- (BOOL) isListening
{
    return self.active;
}

- (void) handleEvent: (int) event
{
    //do something with event
}

@end

Instantiation

Once you have defined a class, you will want to create an instance of it.

In both C++ and Java, the instance would look like this:

Animal* beaver = new Animal();

While Objective-C would use this:

Animal* beaver = [Animal alloc];

Messaging

The use of those brackets around the call to alloc is known as messaging, one of the interesting features of Objective-C. It is basically the way you call functions on Objective-C objects. Although the syntax may be new, the concept is the same as a function call in C++ or Java. The preceding example calls the new function on the Animal class, which will return a newly allocated instance of that class.

Predictably, you could now call functions on that object, like so:

BOOL listening = [beaver isListening];

In C++, the preceding code would look like this:

bool listening = beaver->isListening();

And in Java, it would look like this:

boolean listening = beaver.isListening();

Sending parameters is also possible. Parameters are separated by colons:

[beaver handleEvent: EVT_EXAMPLE ];

In C++, the preceding code would look like this:

beaver->handleEvent( EVT_EXAMPLE );

And again in Java:

beaver.handleEvent( EVT_EXAMPLE );

One of the additions of messaging is keywords. Each parameter after the first is preceded by a keyword. If the Animal class also had a function called findFood that expected an amount of food to find and a flag to indicate only vegetables were allowed, you might see this:

[beaver findFood: 50 vegetablesOnly: true];

The same function in C++ would look like this:

beaver->findFood(50, true);

Although this makes function calls use more room on the screen, it also attempts to make reading them easier. You do not need to look up the function definition or rely on an IDE’s code completion feature to understand the nature of the values passed in.

You can also nest messages by inserting another set of brackets where a parameter would go. If the Animal class had a function BOOL -isVegetarian, you might see this:

[beaver findFood: 50 vegetablesOnly: [beaver isVegetarian]];

In C++, it would look like this:

beaver->findFood(50, beaver->isVegetarian());

Note

The Objective-C equivalent to a const or factory method in C++ or Java is to use + in front of the method name in the @interface section. This allows you to call the function on the class itself without the need for an instance of the class.

For example:

@interface Animal
    + (BOOL) canAnimalsTalk;
@end

can be called this way:

[Animal canAnimalsTalk];

These are called class methods in Objective-C, since they are called directly on the class itself instead of an instance of the class. Functions declared this way cannot make use of the class’s member variables.

Member Variables

Objective-C provides a number of ways to access class member variables. The first way uses messaging, where the name of the function is the same as the name of the member variable being accessed. This is called an accessor function, and it would be similar to writing get and set functions in C++ or Java. The functions are created automatically when you use the @synthesize keyword in the @implementation section of the class and @property when defining it in the .h file.

The usage syntax looks like this:

int example = [beaver foo]; //returns the value of int foo

[beaver setFoo:10]; //sets the value of int foo to 10

Notice that the name of the automatically generated setter method is set followed by the variable’s name with the first character in uppercase. You can also use dot notation for the same purpose, like so:

int example = beaver.foo; //returns the value of int foo

beaver.foo = 10; //sets the value of int foo to 10

Note

Just like the this keyword in C++ and Java, the self keyword is available inside Objective-C class methods.

Memory Management

Since Objective-C is a superset of C, all of the rules regarding malloc and free still apply. On the iPhone, there is no Garbage Collector that takes care of all objects for you, like the one in Java does, so it is possible to have memory leaks if allocated memory is not properly deallocated.

However, Objective-C does implement a reference counter inside the base class NSObject. Therefore, any class that inherits from NSObject (and most will) has the same reference counting functionality built-in. Specifically, the copy, new, retain, release, autorelease, and alloc methods provided by NSObject are what get the job done.

Whenever an NSObject subclass instance is created using the alloc method or any function with new or copy at the beginning of its name, it will be created with a reference count of 1. You can use the retain function to increment the value by one, and the release and autorelease functions to decrement the value by one. Once the reference value has reached 0, the object will be removed from memory.

If you call retain on an object, you will leak memory if you do not also call release or autorelease on that object because the reference count will never reach 0.

Constructors and Destructors

Like C++, Objective-C classes support the concept of constructor and destructor functions, but with some slight variation. When an object is allocated, the programmer must call the initialization function manually. By default, initialization functions are named init.

The following code is typical of Objective-C:

Animal* beaver = [[Animal alloc] init];

When an Objective-C class is destroyed from memory, its dealloc function will be called, similar to a destructor. If you overload the dealloc function in your class, you must also call the dealloc method of the superclass or it may leak memory:

-(void) dealloc {
    //perform destructor code here
    [super dealloc];
}

Interface Builder Integration

Because Objective-C and Interface Builder are used together for iPhone apps, two macros have been included to allow you to link Objective-C code to Interface Builder views: IBOutlet and IBAction.

By putting IBOutlet in front of UI variables and IBAction in front of class methods, you allow Interface Builder to know what variables and functions your code has made available for its use:

@interface myWindow
{
IBOutlet UIImageView *backgroundImage;
IBOutlet UIWindow *window;
IBOutlet UISwitch*soundToggle;
}
- (IBAction) playgame;
- (IBAction) toggleSound:(id) sender;
- (IBAction) handleEvent:(id) sender forEvent:(UIEvent*) event;
@end

At compile time, IBAction is replaced with void, and IBOutlet is simply removed. They are used only to determine which methods and variables show up in Interface Builder and have no runtime effect.

Mixed C++ and Objective-C

Because Objective-C is a superset of the C language, you can write portions of your code entirely in C. But the Objective-C compiler also allows you to use C++ in your projects. It is possible to use C, C++, and Objective-C syntax in the same file. Files that contain C++ implementations should use the extension .mm instead of .m.

Get iPhone Game Development now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.