In this chapter, you’ll build a small Hello World application and run it in iPhone Simulator. If you’re enrolled in the iOS Developer Program, you’ll even get to run the application on your iOS device. I’m going to take you through this step by step, just to give you an idea of how Xcode and Interface Builder work together.
Enrolling in the iOS Developer Program is separate from registering as an iOS developer. Enrollment ($99 or $299 per year, depending on which program you join) provides you with the software certificates and online provisioning tools needed to run your own apps on your own iOS device and submit them for approval to the App Store. See Chapter 2 for more information on registering and enrolling.
I talk in detail about how Objective-C applications are normally structured in Chapter 4. However, in this chapter, although I do get into Objective-C’s sometimes-quirky syntax, I’m going to give you a higher-level overview of the language to get you going quickly.
If you’ve heard someone explain object orientation before, the distinction between the terms class and object may not be totally clear. However, there is a difference. A class is the blueprint for objects; each time you create an object, the class definition determines its structure. An object is a collection of operations (methods) and information (data) that occupies space in memory and can be instructed to perform operations (invoke methods) on that information.
For those of you who are new to programming, the following list defines some of the terms you’ll come across frequently:
UIViewController
class to manage the view (i.e., UI) you present to the user of your application. You also might create an instance of that class named myViewController
to actually carry out the work of managing the view presented to the user. This would then be referred to as the myViewController
object. An instance of a class should not be confused with its implementation, which is the realization of the class in code.
UIViewController
class to manage your views, instead of using the class directly. The subclass of the standard view controller inherits all of the properties of its parent class, but in addition, it allows you to implement code to handle the specific view presented to the user, such as data entry and validation.
foo
, the value of foo
can be different for objects for the same class. Changing the value of an instance variable in one object will not affect the value of the same variable in all the other objects of that class. Conversely, only a single copy of a class variable exists. If you change the value of a class variable from one object, the value of that variable will change for all the objects of that class.
For those of you coming from an object-oriented background, there are a number of differences between the Objective-C model of object orientation and the one implemented by Simula-derived languages such as C++, Java, and C#.
While its nonobject operations are identical to C, Objective-C derives its object syntax almost directly from the Smalltalk language. Its object model is based on sending messages to object instances; in Objective-C you do not invoke a method, but instead send a message. What’s the difference? Invoking a method implies that you know something about that method. Sending a message leaves it up to the receiver of the message to figure out what to do with it.
This kind of loosely coupled chain of command means that Objective-C is much more dynamic at runtime than the Simula-derived languages, but it also means it might appear to be insubordinate.
That’s because in Simula-derived languages, you must know the type of an object before you can call a method on it. In Objective-C, this is not the case. You simply send the object a message. The receiving object then attempts to interpret the message, but there is no guarantee of a response. If it doesn’t understand the message, it will ignore it and return nil
. Among other things, this kind of model does away with the need to continually cast objects between types to ensure that you are sending a message that will be understood.
Casting is the process whereby you represent one variable as a variable of another type. This is done both for primitive types (suppose you want to change a float to an integer as part of an integer arithmetic operation), as well as for objects. An object can be cast to another object type if it is a subclass of that type. In Objective-C, objects can be represented by the generic id
type, and you can cast objects to this type without regard for their parent class.
The other main difference is in the way memory is managed. While languages such as Java use garbage collection to handle memory management, in Objective-C memory is managed using reference counting. In the past this was done by hand (see the alloc-retain-release cycle discussion in Chapter 4), but with the introduction of Automatic Reference Counting (ARC) with the arrival of iOS 5, this manual procedure has been much simplified.
While the examples in this book will make use of ARC, it is important to understand what is going on behind the scenes. ARC is a compiler-level feature that simplifies the previous manual management of Objective-C objects; it automatically inserts the appropriate calls into your code at compile time.
Because of this, it is still important to understand manual memory management, especially during the transition from the existing legacy code bases to ARC-native code, as many external libraries will not be compatible with ARC. We’re therefore going to be discussing manual memory management in Chapter 4.
Finally, the applications are almost invariably based on the Model-View-Controller (MVC) design pattern, which is pervasive in the Cocoa Touch and other frameworks that you’ll use to build iOS applications. Rather than encouraging you to create subclasses, the MVC pattern makes use of delegate classes. A pattern is a reusable solution to a commonly occurring problem; in object-oriented programming, patterns usually describe how the developer should model the application in terms of the classes that are used, and how the developer should structure the interactions and relationships between these classes.
For example, the root UIApplication
class implements the behavior necessary for an application, but instead of forcing you to subclass the UIApplication
class for your own application and add your own code to the subclass, it delivers notification messages of events to an assigned delegate class that implements the UIApplicationDelegate
protocol. The UIApplication
class asks the delegate class to respond to events when they occur.
I’ll dive a bit deeper into Objective-C as we go through the book, but to make it through this chapter, all you really need to know is that while variable declarations look much the same as variable declarations do in other languages, method calls are surrounded by square brackets. So, for example, both of the following lines of code are method calls:
[anObject someMethod];[anObject someMethod: anotherObject];
Despite the sometimes-quirky syntax (including the square brackets and colon shown in the preceding code) that Objective-C has inherited from Smalltalk, the logic of what is going on should be clear, and we’ll discuss the syntax in much greater detail in the next chapter.
Now let’s create our first application in Xcode. Launch Xcode by double-clicking its icon (it’s located in the /Applications folder on your hard drive). Click “Create a new Xcode project” in the Xcode welcome window.
If you don’t see a welcome window when you start up Xcode, you can create a new project by choosing File→New Project.
This will open an Xcode Project window with a drop-down window that will allow you to choose the type of project we’ll be building. We want to build a “Single View Application,” which is one of iOS Application templates supplied by Xcode (see Figure 3-1).
If it’s not already selected, click on the Single View Application template, and then click on the “Next” button. You should then be presented with something that looks a lot like Figure 3-2. In the Product Name box, enter HelloWorld; this will be the name of both the Xcode project and the application target.
You should make sure you don’t put a space between Hello and World as part of your Project Name, as this can confuse some versions of Xcode.
In the Company Identifier box, enter the root part of your Bundle Identifier [see the section on Creating an App ID in Chapter 2 for more details]. For me, this is uk.co.babilim
. You should leave the Class Prefix box blank, and ensure that the Device Family is set to iPhone and the checkbox for ARC is ticked, and the boxes for storyboard and unit tests are not (see Figure 3-2).
Once you’ve filled in the Configuration panel, click on the Next button to proceed. You should then be presented with another dialog to save your new project (see Figure 3-3). You’ll notice that Xcode will create a local Git repository for your project if you want it to. For now at least, let’s ignore that option. Click Create to create and save your first Xcode project.
Xcode will now open a project window, as shown in Figure 3-4. The left pane shows the classes and other files associated with the project, organized into groups in what’s called the Project Navigator. If you click on the arrow next a group icon (represented as yellow folders), the group will expand to show you the files it contains.
The application template you choose determines how the groups are arranged, but you can move the files around and create your own groups if you prefer to organize things differently. The main group at the top of the Project Navigator window is named after your project, and it contains all the classes that make up the application including the .xib files that the Interface Builder application uses to describe your application’s user interface.
The middle pane is the Editor window; by default, the project will open with the Editor window showing the contents of the Project file (the blue document at the top of the Navigator window). This project file contains all the metadata associated with your project. If you click on one of the source code files, which have postfixes .m or .h, you’ll see that the Editor window fills with more familiar source code.
The righthand pane is the Utilities window. Right now, this is empty, but it gives access to Quick Help and other inspectors as well as resources to use in your project. For now, you may want to minimize the utility view by using the Show/Hide button in the Xcode toolbar. See Figure 3-4 above.
When you created the project, Xcode generated a number of files and, along with them, a lot of the boilerplate code you’d otherwise have to laboriously type in. In fact, the project that Xcode generates for you is a complete (if boring) iPhone application. You know those flashlight applications that have proliferated on the App Store? You’ve just written one…
If you click the button in the Xcode toolbar (see Figure 3-4 again), Xcode will compile the application, deploy it into the iPhone Simulator, and then run it. After the application opens, what you see in the simulator should look very similar to Figure 3-5—a simple, blank, gray view.
Let’s look at the files Xcode has generated as part of the template and how it has divided them into separate groups in the Project Navigator view:
The Supporting Files group also contains three launch images: Default.png, Default@2x.png and Default-568h@2x.png. We’ll talk about these in more detail later in Adding a Launch Image.
The HelloWorld-Prefix.pch prefix header file is implicitly included by each of your source files when they’re built; if you need to include a header file in all of the classes in your project, you can add it here. However, it’s unlikely that you’ll need to do this, so you can safely ignore it for the time being. The HelloWorld-Info.plist (property list) file also plays a role in defining the UI. This property list is an XML file that describes basic information about your application for Xcode and the compiler. The main.m file contains the main()
routine; this is the place where your program begins. In this project, the main.m file handles some memory management duties (discussed in Chapter 4) and then calls the UIApplicationMain
function, which is the main controller, responsible for handling the event loop. You’ll almost never have to change anything in the Supporting Files group, as the boilerplate code the template generated should serve you fairly well.
If you open the Mac OS X Finder and navigate to where you saved the project, you’ll be able to see how the project files are organized on disk. Xcode groups do not necessarily correspond to folders on disk.
Figure 3-6 shows a high-level overview of an iOS application life cycle. This illustrates the main elements of a typical iOS application. Most iOS applications make use of the MVC pattern (see Chapter 4 for more details).
When the user launches your application by tapping its icon on the Home screen, the application’s main()
function is called. The main()
routine calls the UIApplicationMain
function, which is the main application controller responsible for handling the event loop. From this point, the heavy lifting is done by the UIKit framework, which loads the UI and starts the main event loop. During this loop, UIKit dispatches events, such as notification of touches and orientation changes, to your objects and responds to commands issued by your application. When the user performs an action that would cause your application to quit, UIKit notifies your application and begins the termination process.
The application delegate is the core class in your application and receives messages from the main event loop. It is responsible for handling critical system messages. For example, the application delegate handles both the applicationDidFinishLaunching:
and the applicationWillTerminate:
messages. Every iOS application must contain an application delegate object.
The view controller class is responsible for providing views, or a set of views, and presenting them to the user. The class also acts as a delegate and manages your application’s response to some of the standard system behaviors (e.g., a change in device orientation), rearranging and resizing the views it manages in response to these system events.
Let’s begin at the beginning, with the definition of the application delegate class. Click on the AppDelegate.h file, which contains the declaration of the class:
#import <UIKit/UIKit.h> @class ViewController; @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) ViewController *viewController; @end
Here we see the app delegate class declaration, also known as the class header file, begins with the @interface
directive and ends with the @end
directive. This is the delegate class that implements the UIApplicationDelegate
protocol and receives messages from the UIApplication
class. Breaking down this interface directive, we see that the class is called AppDelegate
, it’s a subclass of UIResponder
, and it implements the UIApplicationDelegate
protocol.
We declare a UIWindow
object as part of the class, and after telling the compiler that ViewController
is a class using the @class
directive further up, we also declare a ViewController
object. The UIWindow
class defines an object that coordinates the views (the user interface) that we see on the iPhone’s screen. Both of these objects are declared as class properties using the @
property
name directive. Properties are a generic way of declaring the data that a class provides.
Let’s look at the corresponding implementation. Click on the AppDelegate.m file to open it in the Standard Editor:
#import "AppDelegate.h"#import "ViewController.h" @implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithNibName: @"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES; } - (void)applicationWillResignActive:(UIApplication *)application { } - (void)applicationDidEnterBackground:(UIApplication *)application { } - (void)applicationWillEnterForeground:(UIApplication *)application { } - (void)applicationDidBecomeActive:(UIApplication *)application { } - (void)applicationWillTerminate:(UIApplication *)application { } @end
The header files are imported with the class declarations for both the AppDelegate
and the ViewController
classes.
This is the beginning of the declaration of the Hello World application delegate class.
This statement allocates and initializes the main UIWindow
object.
Likewise for the ViewController
object.
Here is the view managed by the viewController
object as the root view of the window.
This makes the window visible using the makeKeyAndVisible
method.
This is the end of the declaration of the Hello World application delegate class.
When looking at the Xcode documentation, you may on occasion be asked to log in to the Apple Developer site, and when attempting to do so receive the error:
"index.HTML" is locked for editing and you may not be able to save your changes. Do you want to unlock it?
Followed by a second error,
The file "index.HTML" could not be unlocked. The file is a remote resource. Try making a local copy.
If you receive this warning, open the Xcode Preferences, click on the Downloads button in the Preferences toolbar, select the Documentation tab, and then the iOS 5.0 Library. Click on the check box, then click the Install Now button. This will download and install the needed documentation locally.
Now let’s examine the implementation’s application:DidFinishLaunchingWithOptions:
method. This is where we can insert our own code to customize the application after it launches. See Chapter 5 and the City Guide application for an example of this sort of customization. At the moment, it contains the following:
self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; self.viewController = [[ViewController alloc] initWithNibName: @"ViewController" bundle:nil]; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible];
You make an object perform an operation by sending a message to the object. Messages are enclosed in square brackets. Inside the brackets, the object receiving the message is on the left side and the message (along with any parameters the message requires) is on the right. The parameters follow the colon [see The Basics of Objective-C Syntax for another example].
Next, let’s look inside the ViewController
class. The interface file for this class is called ViewController.h; the implementation file is called ViewController.m.
Let’s start with the interface file. Click on the ViewController.h file in the Classes group to open the file in the Standard Editor.
Back in AppDelegate.h, the application delegate declared a viewController
property of the class ViewController
(note the capitalization) that right now doesn’t contain any methods or properties of its own:
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @end
However, looking at the header file, you’ll see that the ViewController
class is a subclass of the UIViewController
class. This is the class that provides the fundamental view-management model for iOS applications, and this class is associated in Interface Builder with a nib file (when you create a view-based project, Xcode automatically creates the associated nib file). That nib file contains the UI that will be displayed when we make this view visible.
Although the Interface Builder files end with the .xib extension, Cocoa programmers still refer to them by their old name, nibs.
Next, click on the ViewController.m file in the Classes group and look at the implementation of the class. For now, bear in mind that this subclass relies on its parent class to handle the messages that are left undefined by virtue of being not implemented.
#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } @end
I’ve talked about Interface Builder quite a bit so far, but we haven’t looked at it. Let’s do that now. Interface Builder allows you to create and lay out the UI for your iOS application visually; it stores your application’s interface in a bundle (an XML file that, for historic reasons, is generally referred to as a nib file) containing the interface objects and their relationship with your own code. However, unlike almost all other similar design systems that generate code, nib files are serialized (also known as freeze-dried) objects. In other words, the files contain the ready-to-run object instances, rather than code to generate these objects at compile time.
We can use Interface Builder to associate the laid out UI elements with our own code by connecting outlets, actions, and delegates to the UI elements inside the Interface Builder application. However, to do so, we must first declare the objects and methods in our code as either IBOutlet
s, or IBAction
s where appropriate, and the classes as delegates.
This IBOutlet
or IBAction
symbol doesn’t affect how the code is compiled, but it is a place marker to tell Xcode that this object in the code can be connected to a UI component in Interface Builder. This allows the UI constructed in Interface Builder to receive messages from the code. The corresponding IBAction
declaration on method declarations, which we’ll meet later, is yet another place marker for Interface Builder, allowing us to connect calling actions in response to events happening in the UI to a method. In many instances, a UI element will also have an associated delegate protocol, and we can declare classes to act as delegates to specific UI elements. Our class will then receive messages when the UI element generates events. For instance, in Chapter 5, you’ll see the UITableView
class and associated delegate protocols in action.
Click on the ViewController.xib file. This will open Interface Builder and display the nib file, as shown in Figure 3-7.
When you click on a nib file, the Standard Editor will change to become a visual representation of your user interface. To the left of this, sandwiched between the editing area and the Project Navigator pane, is the dock. The dock shows the Interface Builder objects and placeholders in the nib file (or if using storyboards, the .storyboard file); you can shrink and expand the dock using the button near the bottom of the Editor window (see Figure 3-7).
The Utilities panel to the right provides access to the Inspector tabs, which will allow you to manipulate your objects in the editor, as well as to inspect the connections and other properties of a specific object.
The Constraints button allows us to modify the constraints governing the positioning of user interface items. The left button aligns items, and is the equivalent of choosing Editor→Align. The center button pins items, equivalent of choosing Editor→Pin, while the right button lets you control how constraints are applied when resizing views.
We’ll discuss the details of what’s going on inside Interface Builder in later chapters; for now, we’re just going to add a button and a label to the view. Then we’ll modify our code so that it knows about those elements, and connect those elements to objects in the code. At that point, we’ll have a working Hello World application.
Click on the View icon in the dock, or directly on the view in the Editor panel, to select it, and then pick the Attributes Inspector from the tab bar along the top of the Utilities panel. The Attributes Inspector is the fourth icon along, as shown in Figure 3-8.
Let’s start by changing the rather dull gray background of the view to white. Click on the Background Color box in the View section of the Attributes Inspector to bring up the standard Mac OS X color picker. Push the opacity slider to 100% and change the color to something more interesting. In my case, I picked white, which is only marginally more interesting than gray. Close the color picker; the background of your View window should now be a more interesting color.
Now go to the Object Library (see Figure 3-7) and click and drag a label and a button, Label (UILabel
) and Round Rect Button (UIButton
), onto your view and drop them in a sensible place.
Delete the placeholder text in the label by double-clicking on the label text to select it and then pressing the Backspace key. This will make the label invisible in the view; however, you can see it’s still there as it’s shown in the dock. If you lose track of where you put it, just click on the Label icon in the dock to select it and it’ll be selected in the view.
You should then add some appropriate replacement text for the button. Just double-click on the button as you did for the label, but this time add some text —“Push me!” perhaps (see Figure 3-9).
In Figure 3-9 you can see some blue vertical lines, these are (some of) the constraints dictating how our user interface will be displayed on different shaped screens.
At this point, we need to tell our code about the user interface elements we added to the view. In the Xcode toolbar, change the Editor type from Standard to Assistant (see Figure 3-10). If you’re short of screen space, for instance, if you’re working on a laptop as I am, you might want to shrink the dock and hide the Utilities panel at the same time to give yourself some extra room to work.
You’ll see that changing from the Standard to the Assistant Editor brings up the interface file that corresponds to the nib file we’re modifying inside Interface Builder (see Figure 3-11).
Now Control-click and drag from the label element you dropped into your view, or from the icon representing the label in the dock, to the header file (between the @interface
and @end
markers). A pop-up window will appear to create an outlet. Name your outlet “label” and click on the Connect button (see Figure 3-12).
Afterward, Control-click and drag from the button to your code. This time, change the connection type from Outlet to Action before naming your action pushButton
. This will not only both define and create a method called pushButton:
in your ViewController
object, but also connect the button element in Interface Builder to your code. The pushButton:
method will be called when the “Touch Up Inside” event (which corresponds to a user tapping on and then releasing the button) is triggered in the interface. We’ll use this to change the text associated with the label and tell the world “Hello!”.
After making these connections, your ViewController.h interface code should look something like this (with the changes highlighted for clarity):
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @property (weak, nonatomic) IBOutlet UILabel *label; - (IBAction)pushButton:(id)sender; @end
For now, you should just follow along; we’ll discuss the layout of Objective-C methods in the next chapter.
If you click on the ViewController.m file, you’ll see that in addition to adding code to the interface file, Interface Builder has modified our implementation. The changes it made are highlighted:
#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (IBAction)pushButton:(id)sender { } @end
Interface Builder has automatically synthesized our label
property for us, which will in turn automatically generate accessor methods. Additionally, it has added a pushButton:
method to the code; this is the hook we’re going to use to change the text of the label.
If you look at the documentation for the UILabel
class, you’ll see that all you need to do is to set the text
property to change the text displayed by the label:
- (IBAction)pushButton:(id)sender {
self.label.text = @"Hello World!";
}
We’re done! Make sure the Scheme in Xcode’s toolbar is set to HelloWorld→iPhone 6.0 Simulator, and click on the Run button. If all goes well, this will start iPhone Simulator and run the code. If there are any issues, the build will fail and you’ll see something like Figure 3-13. Xcode will list the problems in the Navigation panel on the left and automatically jump to the first issue in the Editor window. Here, for instance, I’ve “accidentally typed” self.label.foo
rather than self.label.text
in the pushButton:
method.
However, if all goes well, the application should start in the iPhone Simulator, and you should see something more like Figure 3-14.
Congratulations, you’ve written your first iPhone application. Once you’re done, click on the Stop button in the Xcode toolbar to stop the application running. Now let’s get it to work on your iPhone and iPod touch.
Plug your phone into your Mac. After all the work we did in the previous chapter, Xcode should recognize it. Go ahead and change the Scheme from targeting the simulator to targeting your device (see Figure 3-15). As you can see from the figure, in my case, I’m using an iPhone 5.
Click on the Run button in the Xcode toolbar. If all goes well, Xcode should build and deploy onto your iPhone automatically at this stage. You can monitor this process using the Organizer window. When you’re done with the application, remember to click the Stop button in the Xcode toolbar.
Congratulations, you’ve written and deployed your first iPhone application.
If there is a problem, make sure you have completed all the steps needed to use your iPhone or iPod touch for development that we talked about in the preceding chapter, and make sure your device is plugged in and Xcode is aware of it by opening the Organizer window. You should see a green light next to the name of your device in the lefthand pane.