Closer look at files under the Navigation area (iOS 4)

The HelloWorld application has three subfolders: HelloWorld, Frameworks, and Products. Let’s spend some time reviewing what’s under the hood.

HelloWorld folder

The HelloWorld folder is where you spend most of your time writing code and designing the application’s interface. Click the triangle beside the HelloWorld folder to expand the contents so that you can review what it contains. You’ll find one subfolder called Supporting Files and three files: HelloWorldAppDelegate.h, HelloWorldApp-Delegate.m, and MainWindow.xlb.

SUPPORTING FILES SUBFOLDER

The Supporting Files subfolder contains files that support the application. In the HelloWorld project, you can find HelloWorld-Info.plist, InfoPlist.strings, HelloWorld-Prefix.pch, and main.m. HelloWorld-Info.plist is a property list that contains information about the application, as shown in figure 3.5. It contains a number of instructions for your program compilation, the most important of which is the reference to the main nib file used in your program. InfoPlist.strings is a localization string file for your application’s InfoPlist.

Select the project's Info.plist file to show details in the Editor area.


Figure 3.5 Select the project’s Info.plist file to show details in the Editor area.

The HelloWorld-Prefix.pch file contains special prefix headers, which are imported into every one of your source code files.

Main.m comes with standard code generated by the project template, as you can see in the following listing.

Listing 3.1 Main.m file

Listing 3.1 Main.m file

The creation of this main routine is automatic, and you generally shouldn’t have to fool with it at all. But it’s worth understanding what’s going on. You start with an #import directive, which you’ll recall is Objective-C’s substitute for #include. More specifically, you include the UIKit framework, the most important framework in Cocoa Touch. Notice that it’s also in the helloworldxc_Prefix.pch file, but at least at the time of this writing, it’s part of the default main.m file.

Notice that NSAutoreleasePool is created here. Recall that we mentioned this in our discussion of memory management in topic 2. Note that the autorelease pool is released after you’ve run your application’s main routine, following the standard rule that if you allocate the memory for an object, you must also release it.

The UIApplicationMain line creates your application and kicks off the event cycle. The function’s arguments look like this:

tmp1259_thumb

As with the rest of the main.m file, you should never have to change this. But we nevertheless briefly touch on what the latter two arguments mean—although they’ll usually be set to their defaults, thanks to the nil arguments.

principalClassName defines the application’s main class, which is UIApplication by default. This class does a lot of the action and event controlling for your program, topics that we’ll return to in topic 6. The UIApplication object is created as part of this startup routine, but you’ll note that no link to the object is provided. If you need to access it (and you will), you can use a UIApplication class method to do so:

tmp1260_thumb

This returns the application object. It’s typically sent as part of a nested message to a UIApplication method, as you’ll see in future topics. For now, the application does two things to note: it calls up your default .xib file, and it interfaces with your application delegate.

The delegateClassName defines the application object’s delegate, an idea introduced in topic 2. As noted there, this is the object that responds to some of the application’s messages, as defined by the UIApplicationDelegate protocol. Among other things, the application delegate must respond to lifecycle messages: most important, the applicationDidFinishLaunching: message, which runs your program’s content, as we’ll talk more about momentarily.

APPDELEGATE

As you’ve already seen, the application delegate is responsible for answering many of the application’s messages. You can refer to the previous topic for a list of some of the more important ones or to Apple’s UIApplicationDelegate protocol reference for a complete listing.

More specifically, an application delegate should do the following:

■ At launch time, it must create an application’s windows and display them to the user.

■ It must initialize your data.

■ It must respond to "quit" requests.

■ It must handle low-memory warnings.

Of these topics, the first one is the most important to you. Your application delegate files, HelloWorldAppDelegate.h and HelloWorldAppDelegate.m, start your program.

Now that you’ve moved past main.m, you’ll be using classes, which is the sort of coding that makes up the vast majority of Objective-C code. Select HelloWorldAppDelegate.h in the Navigator area to view the source in the Editor area. You can also enable the assistant for the Editor area (choose View > Editor > Assistant). You’ll see that the side-by-side editor view contains the header file in the left section and the source file in the right section, as shown in figure 3.6.

Listing 3.2 shows the HelloWorldAppDelegate header file.

HelloWorldAppDelegate header file and source file under editor assistant view

Figure 3.6 HelloWorldAppDelegate header file and source file under editor assistant view

Listing 3.2 HelloWorldAppDelegate’s header file

Listing 3.2 HelloWorldAppDelegate's header file

Again, there’s nothing to change here, but we want to examine the contents, both to reiterate some of the lessons you learned in the previous topic and to give you a good foundation for work you’ll do in the future.

First, an @interface line subclasses your delegate from NSObject (which is appropriate, because the app delegate is a nondisplaying class) and includes a promise to follow the UIApplicationDelegate protocol. Then @property declares window as a property. Note that this statement includes some of the property attributes, nonatomic and retain. You use the nonatomic attribute to specify that the synthesized getter method return the value directly. The retain attribute means that when a new value is assigned through the synthesized setter method, the old value will be released and the new value will be retained.

This line also includes an IBOutlet statement, which is used to mark the object as usable from Interface Builder. We’ll examine this concept in more depth in the next section; for now, you only need to know that you have a window object already prepared for your application. Although you won’t modify the header file in this example, you will in the future, and you’ll generally be repeating the patterns you see here: creating more instance variables, including IBOutlets, and defining more properties. You may also declare methods in this header file, something that this first header file doesn’t contain.

The following listing shows the application delegate’s source code file, HelloWorldAppDelegate.m.

Listing 3.3 HelloWorldAppDelegate source code

Listing 3.3 HelloWorldAppDelegate source code

The source begins with an inclusion of the class’s header file and an @implementation statement. The window property is also synthesized, which means the setter and getter methods will be automatically added when the program is compiled. Here window =_window means the property window is represented by the instance variable _window.

It’s the content of the application:didFinishLaunchingWithOptions: method that’s of most interest. As you’ll recall, that’s one of the iOS lifecycle messages we touched on in topic 2. Whenever an iOS application gets entirely loaded into memory, it sends an application:didFinishLaunchingWithOptions: message to your application delegate, running that method. Note that there’s already some code to display in that Interface Builder-created window.

Inside the dealloc method, the instance variable _window, which represents the property window, is released for the memory management. (Recall we mentioned that the window property declared in listing 3.2 will be retained through a setter accessor; if there’s no release command here, you’ll end up with a memory leak.)

MAINWINDOW.XIB

MainWindow.xib is an Interface Builder file, more broadly called a nib file. MainWin-dow creates a window, which is the root for your application to draw any other view. This is your connection to the interface design that may be used to easily create graphic interfaces for your project. We’ll discuss it in depth in the next section.

Frameworks folder and Product folder

The Frameworks folder contains all the libraries that will be linked into your project. By default, UIKit. framework, Foundation, framework, and CoreGraphics . framework are automatically added by the template. The Foundation framework gives you access to NS objects, UIKit gives you access to UI objects, and CoreGraphics gives you access to various graphics functions. Later in this topic, we’ll cover the details on how to add a new framework to the project. For now, you can leave this folder the way it is.

The Products folder contains the products when the project compiles or builds. For the HelloWorld project, HelloWorld.app is the only product sitting under this folder. Right now, HelloWorld.app is shown in red, which means this file doesn’t exist yet. You’ll compile the HelloWorld project shortly, which will generate the commpiled application HelloWorld.app.

Building and running an application in Xcode

To compile in Xcode, navigate to Product and choose Product > Build from the drop-down menu. Your program compiles, and with a successful build, it can be launched on the iOS Simulator or an iOS device. Then choose Product > Run, and the iOS Simulator starts it up. Or, you can click the Run button in the top-left corner of the Xcode window. If you try this using the Hel-loWorld project you just created, you’ll see the whole build and run process, resulting in an empty white screen displaying on your iOS Simulator, as shown in figure 3.7.

iOS applications run only on your iOS Simulator (or on the iPhone or iPad device); they can’t be run on your Macintosh directly. Notice that by default the iPhone Simulator is started up. To switch to the iPad Simulator, navigate to the top-left Scheme menu on the Xcode window, choose iPad Simulator, and click the Run button. You’ll see the iOS Simulator displaying the iPad interface.

Build and run the application on the iOS Simulator.

Figure 3.7 Build and run the application on the iOS Simulator.

How to create a universal application

If you try to run the current HelloWorld application on the iPad Simulator, it will end up displaying the small iPhone window in the center of the iPad Simulator. That’s because when you create this project, the project options for Device Family are set to iPhone (refer to figure 3.3).

You could create a real iPad target for this project when creating the new project for the Device Family option. Do this by selecting iPad or Universal (supports both iPhone and iPad). Because you’ve already created the project, there’s another way to update the current project to change the device family to Universal.We won’t cover the details in this topic because the essentials have been covered. Please take this opportunity to practice on your own and gain more knowledge of Xcode by yourself.

If you later want to restart a program that you’ve already compiled, you can do so in one of three ways. You can click the program’s icon, which should now appear in your iOS Simulator. Or, you can choose Product > Run from the Xcode menu. Finally, you can click the Run button in the Xcode window, which builds only if required and then executes your application.

That’s it! With a rudimentary understanding of Xcode now in hand, you’re ready to write code for your first iOS program.

Writing code for HelloWorld

We’ve been promising for a while that you’ll be amazed by how simple it is to write things using the iOS SDK. Granted, the HelloWorld program may not be as easy as a single printf statement, but nonetheless it’s pretty simple, considering that you’re dealing with a complex, windowed UI environment.

As promised, you’ll write everything inside the application:DidFinishing-Launching method, as shown in the next listing. The bolded code is the extra code you need to display "Hello, World!" on a window.

Listing 3.4 Presenting HelloWorld on the screen

Listing 3.4 Presenting HelloWorld on the screen

Because this is your first look at real live Objective-C code, we’ll examine everything in some depth. You start by sending a message to the window object, telling it to set the background color to red. Recall back in the AppDelegate’s header file, Interface Builder created the window. The IBOutlet that was defined in the header allows you to do manipulations of this sort.

Note that this line also makes use of a nested message, which we promised you’d see with some frequency. Here, you make a call to the UIColor class object and ask it to send the red color to the receiver, which then passes that on to the window. In this topic, we hit a lot of UIKit classes without explaining them in depth. That’s because the simpler objects all have standard interfaces; the only complexity is in which particular messages they accept. If you ever feel you need more information about a class, look at topic A, which contains short descriptions of many objects, or see the complete class references available online at http://developer.apple.com (or in Xcode, select the class name for which you wish to find the defination, navigate to View > Utilities, and choose Quick Help. You should be able to see the documentation related to the class shown on the Utility area under the Quick Help section).

You next define where the text label is placed. You start that process by using CGRectMake to define a rectangle. Much as with Canvas, the iOS drawing uses a grid with the origin (0,0) set at the upper left. Your rectangle’s starting point is 50 to the right and 50 down (50,50) from the origin. The rest of this line of code sets the rectangle to be 150 pixels wide and 40 pixels tall, which is enough room for your text.

You’ll use this rectangle as a frame, which is one of the methods you can use to define a view’s location. Where your view goes is one of the most important parts of your view’s definition. Many classes use an initWithFrame: method, inherited from UIView, which defines location as part of the object’s setup.

The frame is a rectangle that you’ve defined with a method like CGRectMake. Another common way to create a rectangular frame is to set it to take up your full screen with the following code snippet:

tmp1266_thumb

Sometimes you’ll opt not to use the initWithFrame: method to create an object. UIButton is an example of a UIKit class that instead suggests you use a class factory method that lets you define a button shape.

In a situation like that, you must set your view’s location by hand. Fortunately, this is easy to do, because UIView also offers a number of properties that you can set to determine where your view goes, even after it’s been initialized. UIView’s frame property can be passed as a rectangle, like the initWithFrame: method. Alternatively, you can use its center property to designate where the middle of the object goes and the bounds property to designate its size internal to its own coordinate system. All three of these properties are further explained in the UIView class reference. Note that CGRectMake is a function, not a method. It takes arguments using the old, unlabeled style of C, rather than Objective-C’s more intuitive manner of using labeled arguments. When you get outside of Cocoa Touch, you’ll find that many frameworks use this older paradigm. For now, all you need to know is what it does and that you needn’t worry about releasing its memory. If you require more information, read the section "Using Core Foundation" in topic 9.

The label is a simple class that allows you to print text on the screen. Figure 3.2 shows what the label (and the rest of the program) looks like.

As you’d expect, your label work begins with the creation of a label object. Note that you follow the standard methodology of nested object creation that we introduced in the previous topic. First, you use a class method to allocate the object, and then you use an instance method to initialize it. Afterward, you send a number of messages to your object, this time using the dot syntax. We offer this as a variation from the way you set the window’s background color. If you prefer, you can use the dot shorthand of _window.backgroundColor there, too. The two ways to access properties are equivalent.

The most important of the messages sets the label’s text. You also set a font size and font color. You can even give the text an attractive black shadow, to demonstrate how easy it is to do cool stuff using iOS’s objects. Every object that you use from a framework is full of properties, methods, and notifications that you can take advantage of. The best place to look up all these is the class references in Quick Help.

The final steps in your program are all pretty simple and standard. First, you connect the label and the window by using the window’s addSubview method. This is a standard (and important!) method for adding views or view controllers to your window. You’ll see it again and again.

Do you remember the standard rule that you must release anything you allocated? Here, that’s the label. And that’s a simple HelloWorld program, completely programmed and working, with some neat graphical nuances. Now click the Run button on Xcode’s toolbar, and enjoy your first application running in the iOS Simulator (see figure 3.8)!

Although it was sufficient for this purpose, HelloWorld didn’t make much use of the class creation that’s possible in an object-oriented language. Sure, you depended on some existing classes—including UIColor, UILabel, and UIWindow—but all of your new code went into a single function, and you didn’t create any classes of your own. We’ll address how to create your own class in topic 4, when you start working with new classes.

Creating a project for the iPad is almost identical to creating one for the iPhone. The main difference is that the window is much larger. We won’t cover the iPad files in detail as we did for the iPhone template in the beginning of this section, because they’re almost the same.

Running HelloWorld on the iOS Simulator

Figure 3.8 Running HelloWorld on the iOS Simulator

As mentioned earlier, the primary difference is the size of the main window. We’ll discuss the iPad interface and universal application further in topic 7.

So far, you created your first iOS application with Xcode and pure Objective-C code. Now that you’re familiar with the basics of Xcode, let’s move on to the next most important tool for iOS application development under Xcode: Interface Builder.

Next post:

Previous post: