O'Reilly logo

iPhone Game Development by Paul Zirkle, Joe Hogue

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 1. Introduction to the iPhone

The iPhone is one of the most distinctive game platforms currently available. The touch screen, integration with iTunes, programming in Objective-C, low development cost, and ease of publishing all make for a very strange but promising new development opportunity. As the newest kid on the block, the iPhone instantly captured a noticeable portion of the mobile phone market and inspired a wave of copycat devices by makers such as Motorola, Samsung, and LG.

As a programmer, you might not be impressed with sales figures and market shares, but you should be interested in the viability of the iPhone as a whole. If no one owns an iPhone, no one will buy the games you make for it. The good news is that even in the face of the 2009 economic downturn, iPhones continued to sell.

To get started with the iPhone, you’ll need to get a free Apple developer account. Next you’ll download the iPhone SDK on your Mac, which also contains the Xcode IDE and Interface Builder tool for laying out screens. (Apple doesn’t provide a toolkit for Windows or any other non-Mac platform.) And because the iPhone API requires you to write in Objective-C, you will need to read a primer on the language if you do not already understand it. This chapter takes you step by step through all of these tasks.

Apple Developer Account and Downloading the SDK

The first step in setting up your iPhone development environment is to register an Apple developer account. Signing up for an account is free and gives you access to Apple’s online documentation, tutorial videos, and the SDK download:

  1. Go to http://developer.apple.com/iphone/.

  2. Click the Register link, and then click Start Now. Choose the option to create a new Apple ID, or to log in using an Apple ID from an iTunes or App Store account.

  3. Once you have registered, you can log in to the iPhone Dev Center.

  4. Apple may already have emailed you a link to download the free SDK, or you may choose to download the SDK using the link from the website. Note that you should not download Xcode separately because it is included within the SDK download package (and the version of Xcode that comes with the SDK may be newer than what is otherwise available).

  5. Once downloaded, install the SDK, which will make Xcode and Interface Builder accessible to you in the /Developer/Applications folder on your hard drive (you can also activate Spotlight and search for Xcode and Interface Builder to launch either application quickly).

The free developer account will allow you to build applications and run them in a simulator on your Mac. However, to load your application onto a phone, you will also need to sign up for the paid developer program. This requires a small annual fee, so even if you are a private developer, it won’t hurt your wallet too much:

  1. Go to http://developer.apple.com/iphone/program/apply.html.

  2. You will have two options: Standard Program and Enterprise Program. If you are writing games for the general public, you probably do not want the Enterprise Program. If you read closely, you will notice the Enterprise Program is actually for creating applications that only you and your company will use internally. If you plan to create games that will be sold via the App Store, rest assured that the Standard Program is the correct choice for you.

  3. Select Enroll Now and log in if necessary.

  4. You now have another choice: enroll as an individual or as a company. If you choose Individual, you will not be able to add other programmers or quality assurance members to your account, which is necessary to distribute your application to others during the development and testing process. However, if you select Company, you will be required to provide detailed information about your company.

  5. Continue through the website, selecting the appropriate information, until you arrive at a screen that says “Thank you for submitting your enrollment.” Now you must wait for an email from Apple (which may take on the order of a month to arrive).

Note

Signing up for the paid developer program will also give you access to beta releases of future versions of the iPhone OS and SDK, but only during the times at which Apple chooses to make them available.

It is good to get your paid developer account enrollment going as soon as possible so that it will be available when you actually need it.

Application Bundles

When you build an application using Xcode, the end result is called an application bundle. In Mac OS X and the iPhone, an application bundle is a special type of directory that holds an executable file and the resources needed to run it. This includes an icon to represent the application, files with special information about the application, and any images or sounds the application uses.

Note

In the Finder, an application bundle simply appears as its application icon; right-click or Ctrl-click on it and select View Package Contents from the menu to see what’s inside.

Although you can’t do this on the iPhone, you can find iPhone applications in the iPhone Simulator. If you have the iPhone SDK installed, you can use Spotlight to search for the MobileSafari.app file. Show this file in the Finder (don’t try to run it on your Mac), and view its package contents (some of which appears in the following list).

A typical iPhone application bundle might have the following structure:

Executable

(Required.) This is the compiled code executable; it will typically have the same name as your application. In MobileSafari.app, this is the file named MobileSafari.

Info.plist

(Required.) This is a collection of properties, in key-value pair form, that specifies important information about your application. Notable properties listed here are the display name of your application, the version number, and a unique ID number. These files use a binary format that can’t be read in a text editor, but you can use the Property List Editor located in /Developer/Applications/Utilities to view them.

icon.png

(Required.) This is a 57×57 pixel icon used to represent your application on the iPhone’s home screen. Glossy button effects will be added on top of this image automatically, so it should be flat-colored.

Various resources

(Optional.) All common resource files, such as images, sounds, and binary data, used by your application will be placed in the same folder as the executable. The only subfolders present in an iPhone application bundle are for localized resources.

Localization folders

(Optional.) If your application supports multiple languages, you may add subfolders to the bundle, which contain resources that cater to individual languages. The folder names will have a language name or an ISO language abbreviation followed by “.lproj”; for example, English.lproj, French.lproj, German.lproj, and uk.lproj would each contain resources specific to English, French, German, and UK English languages, respectively.

Settings.bundle

(Optional.) You will create this file if you want your application to provide user preference options in the Settings application that comes with the iPhone.

Icon-Settings.png

(Optional.) If you added a Settings.bundle file, this image is used to represent the application in the Settings application. The image should be 29×29 pixels. However, if you do not add this image, the Icon.png image will be scaled and used automatically.

MainWindow.nib

(Optional.) Created by the Interface Builder application, MainWindow.nib contains code and resources necessary to draw your application as it starts up. More .nib files can be loaded after this one, but it will always be the first in memory.

Default.png

(Optional.) This image is displayed as the application is loading the MainWindow.nib file. It should be full screen, which is 480×320 pixels on the iPhone. If this image is close to what the user will see when the application is finished loading, the load process will appear to take less time.

iTunesArtwork

(Optional.) If you are distributing the application outside the App Store, this artwork is used to display your application when loading onto a handset using iTunes. More on this later.

As you will see in the next section, when you’re creating your application, Xcode and Interface Builder will create most of these files for you.

Xcode and Interface Builder

If you are unfamiliar with Xcode, you may be reluctant to learn a new IDE at first. However, the way iPhone development works, you pretty much have to. Fortunately, once you get used to it, you’ll see that Xcode is pretty good at what it does. It has all the features you would expect from an industry-standard IDE: it jumps to the line of compile errors, auto-completes complicated API methods, and has integrated SDK references.

And it gets better: Xcode supports on-device debugging, a full-featured iPhone Simulator, useful project wizards, refactoring tools, and even direct integration with Subversion revision control repositories.

An Xcode project contains all the code, resources, certificates, and configurations you need to create an iPhone application. To get acquainted with the environment, open your Xcode IDE and follow these steps to create a typical “Hello World” application:

  1. Open Xcode.

  2. Select File→New Project.

  3. In the dialog that opens, select iPhone OS, then View-Based Application (see Figure 1-1), and click Choose.

  4. Name the project “HelloWorld” and click Save.

  5. At this point, you can build and run (click the Build and Go icon in the toolbar). The HelloWorld application shows only a blank gray screen when run in the Simulator, as shown in Figure 1-2.

Selecting View-Based Application
Figure 1-1. Selecting View-Based Application
Empty application in the Simulator
Figure 1-2. Empty application in the Simulator

Not very interesting yet, is it? Before we go on to make this a proper “Hello World” application, here is a quick rundown of the files that were generated when you created the project:

HelloWorldAppDelegate.m, HelloWorldAppDelegate.h

The class held in these files can be considered the main code entry point of the application. The app delegate controls the main window and main View Controller, and is responsible for setting them up for display.

HelloWorldViewController.m, HelloWorldViewController.h

This class in these files holds the main view, and is responsible for showing the horribly uninteresting gray screen. We will be editing it to say “Hello World” soon.

MainWindow.xib

This Interface Builder file results in a .nib file that is placed in your application bundle when the project is compiled. When loaded, it creates the app delegate, and loads the main window and View Controller.

HelloWorldViewController.xib

This file lays out the design for the HelloWorldViewController’s view.

Note

NIB stands for NeXTSTEP Interface Builder, and XIB stands for Xcode Interface Builder. NIB files are dense compiled binary files; XIB files are human-readable XML files. As we mentioned earlier, Xcode compiles XIB files into NIB files. The XIB format was created specifically to solve issues with merging NIB files in projects under source control, since you can diff XML files more easily than binary files.

Now we need to draw the “Hello World” text. We can go about this in several ways:

  • Add a Cocoa UILabel by writing code directly in HelloWorldViewController.m.

  • Add a Cocoa UILabel in Interface Builder to HelloWorldViewController.xib.

  • Define a subclass of UIView, and use a Quartz font rendering in drawRect.

  • Create a texture-mapped font in OpenGL ES to render with.

Let’s start with the first method: adding a UILabel by writing code in HelloWorldViewController.m. A stub method named viewDidLoad is already inside HelloWorldViewController.m, which is a good place to add our code. This method will be called after .nib file loading is done, but before rendering begins:

  1. Replace the viewDidLoad function in HelloWorldViewController.m with the following (this function is commented out by default, so be sure to remove the /* that precedes it and the */ that follows it):

    - (void) viewDidLoad {
        [super viewDidLoad];
        //draw "Hello World" using Cocoa UIKit.
        //grab the screen dimensions
        int w = self.view.frame.size.width;
        int h = self.view.frame.size.height;
    
        //create a text label: the size 100,50 here is arbitrary
        // but it must be large enough to fit the "Hello World" text.
        UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
        //put the label at the center of the screen
        label.center = CGPointMake(w/2, h/2);
        //align the text to the center of the label (default is left)
        label.textAlignment = UITextAlignmentCenter;
        //don't draw the label's background (default is white)
        label.backgroundColor = [UIColor clearColor];
        label.text = @"Hello world!";
        //add label to our view, so that it can be rendered
        [self.view addSubview:label];
        //since we alloc'd label in this method we need to release label here
        [label release];
    }
  2. Build and run the project (if you haven’t quit the Simulator from its previous run, you’ll be prompted to stop it). The app should now display your text (see Figure 1-3).

“Hello world!” text shown
Figure 1-3. “Hello world!” text shown

Now let’s go over the second method, adding a UILabel to HelloWorldViewController.xib using Interface Builder. You must undo your changes if you followed the preceding example:

  1. Open the HelloWorldViewController.xib file in Interface Builder by double-clicking it from the list of project files in Xcode.

  2. Double-click the View object to begin editing it (Figure 1-4).

Double-clicking the View object to edit the file
Figure 1-4. Double-clicking the View object to edit the file
  1. Find the Label object in the Library panel (open the panel by selecting Tools→Library Panel, if it is not already open). See Figure 1-5.

  2. Drag the label into the View editing window, as shown in Figure 1-6.

  3. Double-click the new label and edit the text to say “Hello World”. You can also edit it from the Attributes Inspector (Tools→Attributes Inspector).

  4. In the Label Size Inspector (Tools→Size Inspector), click both of the Placement buttons to center the label horizontally and vertically, as shown in Figure 1-7.

  5. Save the .xib file and return to Xcode. Building the application will update the .nib file, which will cause the changes to appear when the application is run, as shown in Figure 1-8.

  6. When the .nib file is loaded, it creates and displays the UILabel. If our code needs access to read or modify the created label, we can link it to an IBOutlet in our code. In HelloWorldViewController.h, replace the stub definition of HelloWorldViewController with the following:

    @interface HelloWorldViewController : UIViewController {
        IBOutlet UILabel* myLabel;
    }

    An IBOutlet is a code tag that enables Interface Builder to recognize possible handles in code that can be linked to.

Selecting Label from the Objects Library
Figure 1-5. Selecting Label from the Objects Library
  1. To link the .nib’s label to the outlet, open HelloWorldViewController.xib in Interface Builder and open the Connections Inspector (Tools→Connections Inspector). Then, click to select the label, drag the label’s New Referencing Outlet to the File’s Owner object, release, and click on the “myLabel” text that shows up in the pop-up menu (see Figures 1-9 through 1-11). Because we set the Referencing Outlet, the two objects will be linked together when the .nib is loaded. Specifically, when HelloWorldViewController.nib is loaded in the application, it will know to set the variable myLabel to point at the UILabel we just linked to.

  2. Save HelloWorldViewController.xib and quit Interface Builder.

Adding a new label to the view
Figure 1-6. Adding a new label to the view

Now our code has access to the label through myLabel. This linking process is used frequently in Interface Builder to specify outlets, actions, delegates, and data sources. Any interaction between visible elements of the interface and your code is made via Interface Builder links.

Modifying the Label object properties
Figure 1-7. Modifying the Label object properties
“Hello World!” text with Label object
Figure 1-8. “Hello World!” text with Label object
The Label Connections window
Figure 1-9. The Label Connections window
Clicking and dragging from New Referencing Outlet to File’s Owner
Figure 1-10. Clicking and dragging from New Referencing Outlet to File’s Owner
Selecting “myLabel” from the pop-up window
Figure 1-11. Selecting “myLabel” from the pop-up window

Views and Controllers

The UIView class represents a View object in the iPhone SDK. Views are visible rectangular portions of the screen that handle drawing and animation, event handling, and subview management. If you look at the iPod application that comes with your iPhone, you’ll see that the navigation bar at the top, the tab bar at the bottom, and the content area in the middle are three separate views.

When creating a view-based application in the New Project Wizard, start with a single View Controller and a single View. You may want more Views as your application becomes more complex. For example, you may have one View for your game, another for a Main menu, one for a Settings screen, and another for an online High Score screen.

If your Views share a lot of the same code, it makes sense to add those Views to the same View Controller, along with the shared code. In the preceding example, we may want to put the Main menu and the Settings in the same View Controller, but put the main Game state and High Score screen each in their own View Controller. Nothing is stopping us from putting them all in one View Controller, or using a different View Controller for each one; it’s purely an organizational consideration.

Adding a new View and View Controller to an existing window

Follow these steps to add a new View and View Controller to an existing window:

  1. In Xcode, create a new class that extends UIViewController. We are calling ours TestViewController.

  2. Create a new XIB file by selecting File→New File and choosing View XIB from the User Interfaces section, as shown in Figure 1-12.

Adding a new View XIB file
Figure 1-12. Adding a new View XIB file
  1. In Interface Builder, select the File’s Owner icon. In the Identity Inspector, set the Class Identity to TestViewController. If the Identity Inspector window is not open, you can access it from Tools→Identity Inspector. See Figure 1-13.

Editing the class name
Figure 1-13. Editing the class name
  1. Set the View’s Referencing Outlet to the File’s Owner view, the same way we did in the Hello World example earlier (Figure 1-14).

  2. Add a TestViewController instance to your code and label it as an IBOutlet. We are putting it in the app delegate class, TestAppDelegate. In TestAppDelegate.h, the new code will look like this:

    IBOutlet TestViewController* testViewController;
  3. Edit your main window’s XIB file and add a ViewController object by dragging it from the Library window into the MainWindow.xib window. You can find the ViewController object in the Library under Library→Cocoa Touch Plugin→Controllers, as shown in Figures 1-15 and 1-16.

Linking to the File’s Owner object
Figure 1-14. Linking to the File’s Owner object
  1. Edit this object to change the name of the class and the NIB to load to “TestViewController”. Do this by selecting the ViewController object in the MainWindow.xib window and editing the class name in the Identity Inspector window. Next, select the Attributes button in the same window to switch it from the Identity Inspector to the Attributes Inspector. Finally, edit the NIB name in the Attributes Inspector (Figures 1-17 and 1-18).

  2. Link this object’s Referencing Outlet to the IBOutlet in TestAppDelegate that we created earlier: testViewController. See Figure 1-19.

  3. Use the following code to add the View object to the Window object before it can be displayed:

    [window addSubview:testViewController.view];
  4. Once the View object has been added to the Window object, activate it by calling:

    [window bringSubviewToFront: testViewController.view];
Adding a View Controller from the Library
Figure 1-15. Adding a View Controller from the Library
Modifying the ViewController object
Figure 1-16. Modifying the ViewController object
Editing the class name
Figure 1-17. Editing the class name
Editing the NIB name
Figure 1-18. Editing the NIB name
Linking to TestViewController
Figure 1-19. Linking to TestViewController

Note that only one View can be active at any time. Calling bringSubviewToFront will remove the currently active View from the responder chain. It will not show up on the foreground or receive input events until you call bringSubviewToFront on it again.

Adding a new View to an existing View Controller

Follow these steps to add a new View to an existing View Controller:

  1. Open the View Controller’s .h file in Xcode and add an IBOutlet UIView pointer for the new View. Ours is named secondView. The code will look like this:

    IBOutlet UIView* secondView;
  2. In Interface Builder, open the View Controller’s XIB file window and add a UIView object from the Library. You can find UIView under Library→Cocoa Touch Plugin→Windows, Views & Bars, as shown in Figure 1-20.

    Adding a View object from the Library
    Figure 1-20. Adding a View object from the Library
  3. Set the UIView’s Referencing Outlet to the IBOutlet you created earlier, secondView.

  4. For organizational purposes, you may wish to name the UIView object in the View Controller’s XIB file window.

  5. To switch to the new View, somewhere in the View Controller, call this:

    self.view = secondView;

Since we are overwriting the View Controller’s view property here, we will want to make sure we have another reference to the old View in case we want to switch back to it. We typically put each UIView into its own IBOutlet, and additionally assign the initial startup UIView into the view property. You can have more than one Reference Outlet for any UIView, so the initial View will have outlets named initialView and view.

Proxy objects

Objects inside the NIB have access to properties inside the File’s Owner class. To access properties outside the NIB, you need to use Proxy objects. The Proxy has an associated class name and proxy name, but it does not create an instance of the associated class. You have to pass in a Proxy instance yourself when initializing the NIB file:

//Instead of auto-loading the view controller from the main window NIB,
// load it manually so that we can set up the proxy object.
viewController = [[HelloWorldViewController alloc] init];
//We want viewController to be able to access IBActions in
// HelloWorldViewController and in HelloWorldAppDelegate.
// The File's Owner will be the View Controller,
// and the Proxy named AppDelegate will be the app delegate [self].
NSDictionary*    proxies = [NSDictionary
                     dictionaryWithObject:self forKey:@"AppDelegate"];
                     //link proxy object name to app delegate instance
NSDictionary*    options = [NSDictionary
                     dictionaryWithObject:proxies
                     forKey:UINibProxiedObjectsKey];
                     //set up options with our proxy
[[NSBundle mainBundle] loadNibNamed:@"HelloWorldViewController"
                     owner:viewController options:options];

Loading Devices

Assuming you have finished the process of signing up for the paid developer program, you are now authorized to load applications such as the “Hello World” example onto an iPhone using Xcode. However, you have to jump through a couple more hoops before you can do this.

Since the iPhone is a secured platform, a lot of bookkeeping is required before you can execute your code on the device. You have to sign builds, Apple has to trust your signature, and the device you are loading has to be provisioned for self-signed applications.

You manage signatures, certificates, and provisioning profiles through the online Program Portal on Apple’s website. Once you are a paid developer, you can find it at http://developer.apple.com/iphone/manage/overview/index.action.

The portal has step-by-step guides for each section—generating Certificate Signing Requests (CSRs), creating a distribution profile, adding a device ID, and so on. However, this can be a complex process, so we will go over the general concepts.

Certificates and Profiles

To publish your application to a phone or to the App Store, you need two signed profiles. One is a developer profile, which you use while developing and testing your app. The other is a distribution profile, which you use when sending your finished application off to the App Store to be published. In a corporate setting, the lead programmer might keep track of the developer profile, whereas the production manager might keep track of the distribution profile.

To create these profiles, you need to generate a certificate that has a public and private key. Apple has to sign the certificate for it to be valid, so first you must use Keychain Access on your Mac to create what is called a Certificate Submission Request, which gets sent to Apple’s developer program. When Apple has reviewed and approved your request, you can download the certificate from the Apple Developer Portal website.

Once you have the signed certificate, you will need an Application Identifier (App ID), a Unique Device Identifier (UDID), and the WWDR certificate.

App ID

The App ID is generated on the Developer Portal to be used in a profile and in your application bundle. An App ID looks like this: com.YourGameCo.YourAwesomeGameName. This is called reverse domain notation, and Java and C# programmers may be familiar with it as the format that package names use in those languages.

If you will be making multiple applications, you can use a wildcard format so that the same developer can use one App ID for multiple applications. A wildcard App ID looks like this: com.YourGameCo.*.

When listed in the Developer Portal, the ID may have 10 alphanumeric characters appended to the front. These are for Apple’s internal use and you can ignore them.

After creating an App ID on the Developer Portal, you must open the Info.plist file in your application bundle and replace the default value of the bundle identifier key with your App ID. If you used a wildcard when creating the App ID on the Portal, you should also replace the asterisk (*) with the name of your game when updating the Info.plist file.

UDID

The UDID is a 40-character hex string that you can obtain from the iPhone device you wish to load by attaching it to your Mac and running iTunes or the Xcode Organizer window.

Note

The UDID is used only for the developer profile and is not useful for the distribution profile.

WWDR certificate

Apple’s World Wide Developer Relations (WWDR) certificate is available from Apple at http://developer.apple.com/certificationauthority/AppleWWDRCA.cer. Download and install the certificate so that you can use it to certify builds. The WWDR certificate links your development certificate to Apple, completing the trust chain for your application.

Installing the profile

Once you have these three items, you can download a provisioning profile from the Developer Portal. This file will have a .mobileprovision file extension. Once you download this file, double-click it to install the profile. It should load into Xcode’s Organizer and show up there when you connect your iPhone to your computer. Make sure the profile is listed in the device’s installed profiles.

Keep in mind that an application is limited to the devices listed in its developer profile.

Xcode Configuration

Once you have all the certificates, keys, and profiles installed, you are ready to set up Xcode to compile an application that will run on your iPhone.

Set the code signing profile in Project→Edit Project Settings→Build→Code Signing Identity→Any iPhone OS Device. See Figure 1-21.

Setting the code signing profile
Figure 1-21. Setting the code signing profile

If your provisioning profile does not show up in the drop-down list, you are missing some part of the certificate chain:

  • Private key

  • Signing certificate

  • WWDR certificate

  • Provisioning profile

Change the bundle identifier to match the App ID name in the provisioning profile. Select the Build Clean menu option after any Info.plist changes; otherwise, the changes will not be reflected in the build (see Figure 1-22).

Set Xcode to build for the device, as shown in Figure 1-23.

If everything goes smoothly, you should be able to build and run the application on the device. Xcode will install your app on the device during the build process.

If something goes wrong, you won’t see any helpful error messages; you will see “ApplicationVerificationFailed,” which could mean anything went wrong. Here is a list of some common issues that could be the source of an error:

The bundle identifier contains typos or whitespace

The bundle identifier must match the App ID. You must select Build→Clean after modifying the bundle identifier.

Part of the certificate chain is missing

The WWDR certificate is easy to miss.

Your certificate has expired

If everything has been working fine and you suddenly encounter a problem as you get closer to your deadline, you may have an expired certificate.

Sometimes just rebooting the iPhone and reconnecting it will get things back on track.

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.

Conclusion

This chapter provided you with a basic understanding of the Objective-C language and the procedures necessary to write, compile, and run code on the iPhone. We encourage you to read as many tutorials as necessary to round out your knowledge of the language and API. Documents at http://developer.apple.com are particularly helpful, and access is free with your Apple developer account.

However, games can be very complicated applications, and without an understanding of the theory behind game programming, game development will be a very challenging task. If you are new to game programming, reading the next chapter thoroughly before attempting to create your game will benefit you greatly.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required