Chapter 2. Getting Started with Applications

If you’re new to Mac, you might be surprised to find that applications don’t come in the form of .EXE files. The excellent design for which Apple is known in its hardware and graphics extends into its software architecture as well, and includes the way applications are laid out in the file system. The same strategy used in Apple desktop systems carries over into the iPhone.

Apple has adopted the practice of creating modular, self-contained applications with their own internal file resources. As a result, installing most applications is as easy as simply dragging them into your applications folder; deleting them as easy as dragging them into the trash. In this chapter, the structure of applications on the iPhone will be explained. You’ll also get up and running with the free open source tool chain used to build executables, and you’ll learn how to install applications on your iPhone. Finally, you’ll be introduced to the Objective-C language and enough of its idiosyncrasies to make an easy transition from C or C++.

Anatomy of an Application

Apple came up with an elegant way to contain applications in their operating system. As OS X is a Unix-based platform, Apple wanted to make it adhere to basic Unix file conventions, and so the resource forks of olde were no longer sufficient (or efficient for that matter). The challenge was to design a structure that would allow an application to remain self-contained while surviving on a file system that didn’t believe in cheapening its architecture with proprietary workarounds. The result was to treat an application as a bundle inside a directory and use standard APIs to access resources, execute binaries, and read information about the application.

If you look inside any Mac application, you’ll find that the .app extension denotes not a file, but a directory. This is the application’s program directory. Inside it is an organized structure containing resources the application needs to run, information about the application, and the application’s executable binaries. A compiler doesn’t generate this program directory structure, but only builds the executable binaries. So to build a complete application, it’s up to the developer to create a skeleton structure that will eventually host the binary and all of its resources.

The program directory for an iPhone application is much less structured than desktop Mac applications. In fact, all of the files used by the application are in the root of the .app program folder.

drwxr-xr-x    root    admin    Terminal.app/
    -rw-r--r--    root    admin    Default.png
    -rw-r--r--    root    admin    Info.plist
    -rwxr-xr-x    root    admin    Terminal
    -rw-r--r--    root    admin    icon.png
    -rw-r--r--    root    admin    pie.png

The above reflects a very basic iPhone application called MobileTerminal. MobileTerminal is an open source terminal client for the iPhone, allowing the user to pull up a shell and work in a Unix environment (which also must be installed as third-party software). MobileTerminal illustrates all of the major components of an iPhone application:

Terminal.app

The directory that all of the application’s resources reside in.

Default.png

A PNG image (Portable Network Graphics file). When the user starts the application, the iPhone animates it to give the appearance that it’s zooming to the front of the screen. This is done by loading Default.png and scaling it up until it fills the screen. This 320×480 image zooms to the front and remains on the screen until the application finishes launching, at which point it serves as the background for whatever user interface elements are drawn on the screen. Applications generally use a solid black or white background.

Info.plist

A property list containing information about the application. This includes the name of its binary executable and a bundle identifier, which is used by the SpringBoard application to launch it. You’ll see an example property list later on in this section.

Terminal

The actual binary executable that is called when the application is launched. This is what your compiler outputs when it builds your application. Your makefile can copy your binary into the application folder when doing a production build. This chapter will provide an example of this process.

icon.png

An image forming the application’s icon on the SpringBoard (the iPhone’s desktop application). SpringBoard isn’t concerned with the size of the file, and will attempt to draw the image outside of its icon space if it is large enough. Most icons are generally 60×60 pixels.

pie.png

An image resource used by the MobileTerminal application. There are many methods provided by the iPhone framework to fetch resources, and most of them accept only a filename instead of a path. The file supplied to these methods must therefore be stored directly in the program directory. This is consistent with Apple’s effort to keep applications self-contained.

Creating an Application Skeleton

The first thing you’ll need to do before building any applications is to put together a skeleton .app directory to contain it.[1] The skeleton will provide all of the information necessary for the iPhone to acknowledge the existence of your application so it can be run from the SpringBoard.

This book presents many fully functional code examples, and in order to properly run them, you’ll need to build an example skeleton called MyExample.app. Creating the directory is easy enough:

$ mkdir MyExample.app

Next, write a property list to describe the application and how to launch it. The Info.plist file expresses the property list in XML, and should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleExecutable</key>
    <string>MyExample</string>
    <key>CFBundleIdentifier</key>
    <string>com.oreilly.www.iphone.examples</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>1.0</string>
</dict>
</plist>

The most important options above have been bolded. These are the values for CFBundleExecutable and CFBundleIdentifier. The CFBundleExecutable property specifies the filename of the binary executable within the folder. This is the file that gets executed when your application is launched—the output from your compiler. In this example, the filename is the same as the application’s name, but this isn’t absolutely necessary.

The CFBundleIdentifier property specifies a unique identifier by which your application is known. The application layer of the iPhone is more concerned about addressing your application as a whole rather than the binary itself. Whenever SpringBoard (or another application) launches MyExample, it will be referenced using this identifier. The name must be unique among all other applications on the iPhone. It’s common practice to incorporate the URL of your web site to ensure it’s unique.

The application’s icon.png and Default.png files are also copied in. If these are left out, the iPhone will use the worst looking images possible to serve as default images for both. We’ll leave the files out of our example to show you what we mean. Make sure to create and include images with these names when you publish your own applications to make them look professional.

Our skeleton is now good enough to run examples. In the next section, you’ll install the tool chain on your desktop, after which you can get started compiling example applications. In the coming chapters, you’ll build many examples. After each has been built, the binary executable MyExample will need to be copied into your program folder. Your completed application will look like this:

drwxr-xr-x    root    admin    MyExample.app/
    -rw-r--r--    root    admin    Info.plist
    -rwxr-xr-x    root    admin    MyExample

The examples provided in this book generally do not need any additional resources, so images and sounds will be necessary only when the example calls for them. When they do, however, you’ll copy the files required into the MyExample.app directory. Most examples make use of existing files on the iPhone to avoid filling up the book with binary code.

Building the Free Tool Chain

As we discussed in Chapter 1, the iPhone began life as a closed platform. This originally meant that no developer tools were publicly available to build iPhone-native applications. There has been much speculation about whether Apple secretly hoped the community would break into the phone, thus bolstering its status among the geek community. Over the first few months of the iPhone’s life, this is exactly what happened. The open source community successfully cracked the phone and began writing a tool chain to build applications. It has since been released as free software. The tool chain consists of a cross-compiler, a linker, an assembler, a C hook into the assembler called Csu, and class headers for Objective-C frameworks generated by a tool called class-dump.

The tool chain uses a cross-compiler, which is a compiler that runs on one machine (namely, your desktop) but builds executables that can run on a different machine (the arm processor in an iPhone). The commands and path names provided throughout this book presume that you’ve used the procedures from this chapter to build and install the tool chain. The tool chain is updated periodically as new versions of it are released, so its setup can sometimes change. The instructions here will guide you through the steps to install version 0.30 of the tool chain, which is the latest available at the time of this writing. Newer versions are documented on the official tool chain project page at http://code.google.com/p/iphone-dev.

The tool chain builds and installs into /usr/local by default. All of the examples provided in this book will presume that this is where you’ve installed it. If you’ve built the tool chain before, or are just concerned about modifying files there, you’ll want to move your current /usr/local out of the way and start with a fresh directory.

Warning

If you have a previous version of the tool chain, newer versions may not build correctly. To ensure that you start with a clean installation, move your old copy out of the way.

What You’ll Need

While there are some unofficial binary distributions of the tool chain floating around the Internet, you’ll be building it from sources in this section. The following are requirements for building from sources.

Supported desktop platform

The first thing you’ll need is a desktop platform that is supported. Platforms currently supported by the tool chain are:

  • Mac OS X 10.4 Intel or PPC

  • Mac OS X 10.5 Intel

  • Ubuntu Feisty Fawn, Intel

  • Ubuntu Gusty Gibbon, Intel

  • Fedora Core, Intel

  • Gentoo Linux 2007.0, x86_64

  • Debian 2.6.18

  • CentOS 4

Nicholas Penree of Conceited Software (http://www.conceitedsoftware.com) took time to adapt the tool chain’s installation to run on Leopard, which is what we’ll use in our example. Other platforms follow the same basic steps as these. Official tool chain instructions can be found at http://code.google.com/p/iphone-dev/wiki/Building.

High speed Internet connection

The tool chain is several hundred megabytes in size—and that’s just the sources. Unless you want to be sitting around for a few days, you’ll likely want to download the sources over a high-speed connection. If you don’t have one, it might be a good idea to perform the installation from a library or local coffee shop.

Open source tools

The next things you’ll need are the necessary open source tools installed on your desktop:

  • bison (v1.28 or later)

  • flex (v2.5.4 or later)

  • gcc (the GNU compiler that handles C, C++, and Objective-C)

  • svn (the Subversion source control utility)

If you’re missing any of these tools, download and install them before proceeding. On the Mac, these are included with XCode tools, and you’ll want to install or upgrade to the latest version of XCode before proceeding. Most other operating systems provide them as optional components in their distribution.

Tip

XCode tools can be downloaded from Apple’s web site at http://developer.apple.com/tools/xcode/.

iPhone filesystem

Finally, the last thing you’ll need is a copy of your iPhone’s filesystem; specifically, the libraries and frameworks. For dramatic effect, and because our lawyers make us, we’ll display this general disclaimer:

Warning

Installing the tool chain requires that you copy libraries from your iPhone to your desktop. Check with your local, state, and federal laws to ensure this is legal where you reside.

Having installed SSH onto the iPhone in Chapter 1, use the following commands to download the files you need into a folder called /usr/local/share/iphone-filesystem.

# mkdir -p /usr/local/share/iphone-filesystem
# cd /usr/local/share/iphone-filesystem
# mkdir -p ./System/Library ./usr
# scp -r root@iphone:/System/Library/Frameworks/ .
# mv Frameworks ./System/Library
# scp -r root@iphone:/usr/lib .
# mv lib ./usr

Compiling the Tool Chain

The source code for the tool chain is split into two repositories: one for the LLVM compiler framework and one for the rest of the tool chain. Create a build directory for yourself and cd into it. Now, use Subversion to check both projects out from their repositories.

$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm-svn -r 42498
$ svn co http://iphone-dev.googlecode.com/svn/trunk/ iphone-dev

The download may take an hour or longer, depending on the speed of your connection. Once both repositories have been checked out, it’s time to start building.

The instructions in the next sections presume you know how to use a terminal window. On the Mac, this can be found in your Utilities folder inside Applications. It is also assumed that you have some level of knowledge of Unix.

One convention that may be unfamiliar to you is the use of the built-in shell commands pushd and popd. These are similar to the cd command, but they push and pop directories on a stack. This makes it easy to do some work in a new directory and then return to a previous one without having to remember where you were.

You’ll also see references to the sudo command. This is a Unix tool providing limited access to run privileged (root) commands. When you want to run a command that requires privileged access (because it accesses sensitive data on the operating system or could have dangerous effects hurting the operating system), type sudo on the command line followed by the command you wish to run. Mac OS X will then prompt you for the root password to your desktop before allowing the command to run. If you don’t have sudo, you can safely leave it off of your commands, but you’ll first need to invoke su to become root.

Step 1: Build and install the LLVM framework

The LLVM (Low Level Virtual Machine) framework provides a standard infrastructure for building compilers. It provides the necessary hooks and APIs to build a standardized compiler without having to rewrite all of the basic components of a compiler. Issue the following statements to compile and install a release build of the llvm compiler.

$ pushd llvm-svn
$ ./configure --enable-optimized
$ make ENABLE_OPTIMIZED=1
$ sudo make install
$ LLVMOBJDIR=`pwd`
$ popd

Step 2: Build and install cross-compiler tools

The following commands build and install the cross-compiler components of the tool chain. These are specific to Mac OS X, so be sure to read the official documentation if you’re using a different platform.

$ pushd iphone-dev
$ sudo mkdir /usr/local/arm-apple-darwin
$ mkdir -p build/odcctools
$ pushd build/odcctools
$ ../../odcctools/configure --target=arm-apple-darwin --disable-ld64
$ export INCPRIVEXT="-isysroot /Developer/SDKs/MacOSX10.4u.sdk"
$ make
$ sudo make install
$ popd
$ HEAVENLY=/usr/local/share/iphone-filesystem

Step 3: Patch the system headers

The system headers found in your XCode SDK are shared by your desktop and the iPhone platform, but some pre-compiler macros are architecture-specific. Because the iPhone’s architecture is different from the desktop’s, these headers need to be patched to work for the iPhone. Issue the following commands to patch the headers (don’t worry, the originals are automatically backed up).

$ pushd include
$ ./configure --with-macosx-sdk=/Developer/SDKs/MacOSX10.4u.sdk
$ sudo bash install-headers.sh
$ popd

Step 4: Install the Csu

The Csu provides C hooks into assembly’s “start” entry point, and sets up the stack so that your program’s main( ) function can be called. It’s essentially glue code.

$ mkdir -p build/csu
$ pushd build/csu
$ ../../csu/configure --host=arm-apple-darwin
$ sudo make install
$ popd

Step 5: Build and install llvm-gcc

Now that the LLVM framework, cross-compiler tools, and Csu have been built, the compiler itself can now be built and installed. If you’re doing this in stages or have since closed your terminal window, make sure that you’ve still got the environment variables $LLVMOBJDIR and $HEAVENLY set to the proper directories. The LLVMOBJDIR variable points to the location of LLVM object files, which were compiled when you built LLVM. These are used to build llvm-gcc. The HEAVENLY variable points to the location where you copied the iPhone’s libraries onto your desktop. This directory is used by llvm-gcc to link to the iPhone’s framework and library files when you compile applications. The name “heavenly” was the code name given by Apple to the 1.0 code base of the iPhone software. The 1.1 code base is code-named “snowbird,” but the original name is still used in the tool chain.

$ set | grep -e LLVMOBJDIR -e HEAVENLY

If you don’t see output from the previous command, you need to set the environment variables again. Get back into your build directory and run:

$ pushd llvm-svn && LLVMOBJDIR=`pwd` && popd
$ HEAVENLY=/usr/local/share/iphone-filesystem

Once you’ve ensured that these are set, issue the following commands to build and install the compiler:

$ mv llvm-gcc-4.0-iphone/configure llvm-gcc-4.0-iphone/configure.old
$ sed 
  's/^FLAGS_FOR_TARGET=$/FLAGS_FOR_TARGET=${FLAGS_FOR_TARGET-}/g' 
  llvm-gcc-4.0-iphone/configure.old > llvm-gcc-4.0-iphone/configure
$ sudo ln -s /usr/local/arm-apple-darwin/lib/crt1.o 
  /usr/local/arm-apple-darwin/lib/crt1.10.5.o
$ mkdir -p build/llvm-gcc-4.0-iphone
$ pushd build/llvm-gcc-4.0-iphone
$ export FLAGS_FOR_TARGET="-mmacosx-version-min=10.1"
$ sh ../../llvm-gcc-4.0-iphone/configure 
  --enable-llvm=`llvm-config --obj-root` 
  --enable-languages=c,c++,objc,obj-c++ 
  --target=arm-apple-darwin --enable-sjlj-exceptions 
  --with-heavenly=$HEAVENLY 
  --with-as=/usr/local/bin/arm-apple-darwin-as 
  --with-ld=/usr/local/bin/arm-apple-darwin-ld
$ make LLVM_VERSION_INFO=2.0-svn-iphone-dev-0.3-svn
$ sudo make install
$ popd
$ popd

Congratulations! You’ve built the free tool chain for iPhone. You’re now ready to start compiling iPhone applications. The compiler itself can be invoked directly by calling /usr/local/bin/arm-apple-darwin-gcc. We’ll explain how to use it in the next section.

Building and Installing Applications

Now that the tool chain has been installed, the next step is to learn how to use it. There are two essential ways to build an executable: the command line or a makefile.

The examples in this book are simple enough that they can be built using the command line. The tool chain is compliant to standard compiler arguments, and should be familiar if you’ve ever used gcc in the past. You’ll want to make sure /usr/local/bin is in your path before you try to use the cross-compiler.

$ export PATH=$PATH:/usr/local/bin

The anatomy of a typical command line compile is:

$ arm-apple-darwin-gcc -o MyExample MyExample.m -lobjc 
-framework CoreFoundation -framework Foundation
arm-apple-darwin-gcc

The name of the cross-compiler itself. This is located in /usr/local/bin, so be sure you’ve added it to your path.

-o MyExample

Tells the compiler to output the compiled executable to a file named MyExample.

MyExample.m

The name of the source file(s) being included in the program, separated by spaces. The .m extension tells the compiler that the sources are written in Objective-C.

-lobjc

Tells the compiler to link in the tool chain’s Objective-C messaging library, which is needed by all iPhone applications. This library glues C-style function calls to Objective-C messages, among other things.

-framework CoreFoundation -framework Foundation

Two of the base frameworks to be linked into the application. Depending on what components of the operating system are being used in the code, different frameworks provide different layers of functionality. You’ll be introduced to many different frameworks throughout this book.

The command line will suffice for most small applications and examples, but for larger applications, it makes sense to write a makefile. A makefile is a simple text file that acts as a manifest for building applications. It is used by a program called make, which is a portable build utility included with most development kits. The make program is responsible for calling the compiler (and linker) and passing them whatever flags and parameters are needed. Makefiles are logical ways to lay out the composition of an application. They also allow the developer to easily clean up the object files in a directory, create application packages, and perform a number of other tasks useful to building applications.

The previous command line example could be rewritten as a makefile like the one below, named Makefile, and placed into the source directory.

CC = /usr/local/bin/arm-apple-darwin-gcc
LD = $(CC)
LDFLAGS = -lobjc 
          -framework CoreFoundation
CFLAGS =

all:       MyExample

MyExample: MyExample.o
           $(LD) $(LDFLAGS) -o $@ $^

%.o:       %.m
           $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

%.o:       %.c
           $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

%.o:       %.cpp
           $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

Warning

All indentations are actually tabs. Tabs must be used in order for the makefile to work properly.

Once the makefile file is in place, the application’s executable can be built with one simple command:

$ make

In addition to building an application, functionality can be added to copy the application’s executable into the program folder skeleton you made:

package:
          cp -p MyExample ./MyExample.app/

With this added to the makefile, you can run make package to automatically set up your .app directory.

Another popular use for makefiles is to clean the directory so that it can be sent to someone else. You can even tell the makefile to delete the executable that was copied into the program folder.

clean:
           rm -f *.o *.gch
           rm -f ./MyExample.app/MyExample

Installing an Application

Once an application has been built, it can be installed by copying the entire program directory into the /Applications folder on the iPhone. Using the SSH server you set up in Chapter 1, you can do this over WiFi:

$ scp -r MyExample.app root@iphone:/Applications

Before the iPhone will recognize the application, either the iPhone must be powered down and rebooted, or the SpringBoard application must be restarted on the iPhone itself. Log in to the iPhone using SSH and execute the following command to restart SpringBoard:

$ killall SpringBoard

Once restarted, you should see the application on the SpringBoard. Pressing the icon will launch it.

Integrating with XCode

While most developers use the command line or a makefile to build iPhone applications, the tool chain can be partially integrated with XCode to take advantage of the feature-rich editor and one-click build process. XCode treats the tool chain as an external resource and calls it to perform the actual build.

To integrate with XCode, a template is required to glue the necessary pieces to the tool chain. John Robinson from Monster and Friends has designed an XCode template based on one written by tool chain developer Lucas Newman. We’ve made some changes to tailor it to this book. Our version can be found in the download section for this book at http://www.oreilly.com/catalog/9780596518554/. John’s original version can be found at http://www.monsterandfriends.com/?q=node/62.

To integrate the cool chain with XCode, perform the following steps:

  1. Download and install XCode version 3.0 or later from Apple’s developer web site.

  2. Download our version of the template from the O’Reilly web site and extract the archive’s contents.

  3. A folder named iPhone UIKit Application will be created. Copy this directory into /Developer/Library/Xcode/Project Templates/Application on your Mac.

Once you’ve installed the template, you can now create a new iPhone project by performing these steps:

  1. Launch XCode and select New Project from the File menu. A list of templates will be presented to you to choose from.

  2. In the Application section of the list, scroll to the iPhone UIKit Application template and create a new project using it as the template.

A new project will now be created, and the project name will be reflected in the filenames used. To build the application, just click the Build button on the toolbar. XCode will call the tool chain’s compiler and place a binary in the project’s build folder.

Because XCode treats the tool chain as an external resource, it’s not completely integrated with it. What happens under the hood is this: XCode kicks off a build process using a makefile present in the project template. This makefile calls the tool chain’s compiler with the appropriate options. To add new files or frameworks to your project, you’ll need to manually edit the file named Makefile shown in your project’s file list. This will bear a resemblance to the one discussed in the last section.

Transitioning to Objective-C

Objective-C was written in the early 1980s by scientist and software engineer Brad Cox. It was designed as a way of introducing the capabilities of the Smalltalk language into a C programming environment. A majority of the iPhone’s framework libraries are written in Objective-C, but because the language was designed to accommodate the C language, you can use C and C++ in your application as well. Objective-C is used primarily on Mac OS X and GNUstep (a free OpenStep environment). Many languages, such as Java and C#, have borrowed from the Objective-C language. The Cocoa framework makes heavy use of Objective-C on the Mac desktop, which carried over onto the iPhone.

If you’ve developed on the Mac OS X desktop before, you’re already familiar with Objective-C, but if the iPhone is your first Apple platform, then you’re likely transitioning from C or C++. This section will cover some of the more significant differences between these languages. If you have a prior background in C or C++, this should be enough to get you up and writing code using the examples in this book as a guide.

Messaging

The first thing you’ll notice in Objective-C is the heavy use of brackets. In Objective-C, methods are not called in a traditional sense; instead, they are sent messages. Likewise, a method doesn’t return, but rather responds to the message. Unlike C, where function calls must be predefined, Objective-C’s messaging style allows the developer to dynamically create new methods and messages at runtime. The downside to this is that it’s entirely possible to send an object a message to which it can’t respond, causing an exception and likely program termination.

Given an object named myWidget, a message can be sent to its powerOn method this way:

returnValue = [ myWidget powerOn ];

The C++ equivalent of this might look like:

returnValue = myWidget->powerOn(  );

The C equivalent might declare a function inside of its flat namespace:

returnValue = widget_powerOn(myWidget);

Arguments can also be passed with messages, provided that an object can receive them. The following example invokes a method named setSpeed and passes two arguments:

returnValue = [ myWidget setSpeed: 10.0 withMass: 33.0 ];

Notice the second argument is explicitly named in the message. This allows multiple methods with the same name and data types to be declared—polymorphism on steroids.

returnValue = [ myWidget setSpeed: 10.0 withMass: 33.0 ];
returnValue = [ myWidget setSpeed: 10.0 withGyroscope: 10.0 ];

Class and Method Declarations

While C++ classes can be defined in Objective-C, the whole point of using the language is to take advantage of Objective-C’s own objects and features. This extends to its use of interfaces. In standard C++, classes are structures, and their variables and methods are contained inside the structure. Objective-C, on the other hand, keeps its variables in one part of the class and methods in another. The language also requires that the interface declaration be specifically declared in its own code block (called @interface) separate from the block containing the implementation (called @implementation). The methods themselves are also constructed in a Smalltalk-esque fashion, and look very little like regular C functions.

The interface for our widget example might look like Example 2-1, which is a file named MyWidget.h.

Example 2-1. Sample interface (MyWidget.h)
#import <Foundation/Foundation.h>

@interface MyWidget : BaseWidget
{
    BOOL isPoweredOn;
    @private float speed;
    @protected float mass;
    @protected float gyroscope;
}
+ (id)alloc;
+ (BOOL)needsBatteries;
- (BOOL)powerOn;
- (void)setSpeed:(float)_speed;
- (void)setSpeed:(float)_speed withMass:(float)_mass;
- (void)setSpeed:(float)_speed withGyroscope:(float)_gyroscope;
@end

Each of the important semantic elements in this file are explained in the following sections.

Imports

The preprocessor directive #import replaces the traditional #include directive (although #include may still be used). One advantage to using #import is that it has built-in logic to ensure that the same resource is never included more than once. This replaces the round-about use of macro flags found routinely in C code:

#ifndef _MYWIDGET_H
#define _MYWIDGET_H
...
#endif

Interface declaration

The interface is declared with the @interface statement followed by the interface’s name and the base class (if any) it is derived from. The block is ended with the @end statement.

Methods

Methods are declared outside of the braces structure. A plus sign (+) identifies the method as a static method, while a minus sign (−) declares the method as an instance method. Thus, the alloc method (to allocate a new object) will be called using a reference directly to the MyWidget class, whereas methods that are specific to an instance of the MyWidget class, such as needsBatteries and powerOn, will be invoked on the instance returned by alloc.

Every declared argument for a method is represented by a data type, local variable name, and an optional external variable name. Examples of external variable names in Example 2-1 are withMass and withGyroscope. The notifier (calling function) that invokes the method refers to external variable names, but inside the method the arguments are referenced using their local variable name. Thus, the setSpeed method uses the local _mass variable to retrieve the value passed as withMass.

If no external variable name name is supplied in the declaration, the variable is referenced only with a colon, for example, :10.0.

Implementation

The code suffix for Objective-C source is .m. A skeleton implementation of the widget class from the last section might look like Example 2-2, which is named MyWidget.m.

Example 2-2. Sample implementation (MyWidget.m)
#import "MyWidget.h"

@implementation MyWidget

+ (id)alloc {
}

+ (BOOL)needsBatteries {
    return YES;
}

− (BOOL)powerOn {
    isPoweredOn = YES;
    return YES;
}

− (void)setSpeed:(float)_speed {
    speed = _speed;
}

− (void)setSpeed:(float)_speed withMass:(float)_mass {
    speed = _speed;
    mass = _mass;
}

− (void)setSpeed:(float)_speed withGyroscope:(float)_gyroscope {
    speed = _speed;
    gyroscope = _gyroscope;
}
@end

Just as the interface was contained within its own code block, the implementation begins with an @implementation statement and ends with @end. In C++, it is common practice to prefix member variables with m_ so that public methods can accept the name of the variable. This makes it easy to reuse someone else’s code because they can deduce a variable’s purpose by its name. Since Objective-C allows for an external variable name to be used, the method is able to provide a sensible name for the developer to use while internally using some proprietary name. The true name can then be used inside the object, while the method’s local variable name is prefixed with an underscore, e.g., _speed.

Categories

Objective-C adds a new element to object-oriented programming called categories. Categories were designed to solve the problem where base classes are treated as fragile to prevent seemingly innocuous changes from breaking the more complex derived classes. When a program grows to a certain size, the developer can often become afraid to touch the smaller base classes because it’s too difficult by then to determine what changes are safe without auditing the entire application. Categories provide a mechanism to add functionality to smaller classes without affecting other objects.

A category class can be placed “on top” of a smaller class, adding to or replacing methods within the base class. This can be done without recompiling or even having access to the base classes’ source code. Categories allows for base classes to be expanded within a limited scope, so that any objects using the base class (and not the category) will continue to see the original version. From a development perspective, this makes it much easier to improve on a class written by a different developer. At runtime, portions of code using the category will see the new version of the class, and code using the base class directly will see only the original version.

The difference between categories and inheritance is the difference between tricking out your car versus dressing it up as a parade float. When you soup up your sports car, new components are added to the internals of the vehicle that cause it to perform differently. Sometimes components are even pulled out and replaced with new ones. The act of adding a new component to the engine, such as a turbo, affects the function of the entire vehicle. This is how inheritance works.

Categories, on the other hand, are more like a parade float in that the vehicle remains completely intact, but cardboard cutouts and papier-mâché are affixed to the outside of the vehicle so that it appears different. In the context of a parade, the vehicle is a completely different animal, but when you take it to the mechanic, it’s the same old stock car you’ve been driving around.

The widget factory is coming out with a new type of widget that can fly through space, but is concerned that making changes to their base class might break existing applications. By building a category, applications using the MyWidget base class will continue to see the original class, while the newer space applications will use a category instead. The following example builds a new category named MySpaceWidget on top of the existing MyWidget base class. Because we need the ability to blow things up in space, a method named selfDestruct is added. This category also replaces the existing powerOn method with its own. Contrast the use of parentheses here to hold the MySpaceWidget contained class with the use of a colon in Example 2-1 to carry out inheritance.

#import "MyWidget.h"

@interface MyWidget (MySpaceWidget)
- (void)selfDestruct;
- (BOOL)powerOn;
@end

Example 2-3 shows a complete source file implementing the category.

Example 2-3. Sample category (MySpaceWidget.m)
#import "MySpaceWidget.h"

@implementation MyWidget (MySpaceWidget)

- (void)selfDestruct {
    isPoweredOn = 0;
    speed = 1000.0;
    mass = 0;
}

- (BOOL)powerOn {
    if (speed == 0) {
        isPoweredOn = YES;
        return YES;
    }

    /* Don't power on if the spaceship is moving */
    return NO;
}
@end

Posing

In Objective-C, a subclass class can pose as one of its superclasses, virtually replacing it as the recipient of all messages. This is similar to overriding, only an entire class is being overridden instead of a single method. A posing class is not permitted to declare any new variables, although it may override or replace existing methods. Posing is similar to categories in that it allows a developer to augment an existing class at runtime.

In past examples, mechanical widget classes were created. Well, at some point after designing all of these widgets, perpetual energy was discovered. This allowed many of the newer widgets to be autonomous, while some legacy widgets still required batteries. Because autonomous widgets have such a significant amount of different code, a new object called MyAutonomousWidget was derived to override all of the functionality that has changed, such as the static needsBatteries method. See Example 2-4 and Example 2-5.

Example 2-4. Sample interface for posing (MyAutonomousWidget.h)
#import <Foundation/Foundation.h>
#import "MyWidget.h"

@interface MyAutonomousWidget : MyWidget
{

}

+ (BOOL)needsBatteries;
@end
Example 2-5. Sample implementation for posing (MyAutonomousWidget.m)
#import "MyAutonomousWidget.h"

@implementation MyAutonomousWidget

+ (BOOL)needsBatteries {
    return NO;
}
@end

Instead of changing all of the existing code to use this class, the autonomous class can simply pose as the widget class. The class_poseAs method is called from the main program or another high-level method to invoke this behavior:

    MyAutonomousWidget *myAutoWidget = [ MyAutonomousWidget alloc ];
    MyWidget *myWidget = [ MyWidget alloc ];
    class_poseAs(myAutoWidget, myWidget);

At this point, any other methods we’ve replaced in the posing class (to change how we talk to autonomous devices) would pose as the original base class.

Further Study

To learn more about Objective-C programming, check out the following great resources from O’Reilly:

Learning Cocoa with Objective-C, Second Edition, by James Duncan Davidson (Apple Computers, Inc.)

http://www.oreilly.com/catalog/learncocoa2/

Objective-C Pocket Reference by Andrew M. Duncan (O’Reilly)

http://www.oreilly.com/catalog/objectcpr/


[1] Technically, it’s possible to run an application directly from the iPhone’s command line, but this breaks many application-level functions. SpringBoard itself is heavily integrated with the user interface framework, and your applications will need to be assembled and invoked appropriately to make them entirely usable.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.77.76