Advertisement

First Steps with UIKit

by
This post is part of a series called Learn iOS SDK Development From Scratch.
Exploring the Foundation Framework
Table View Basics

UIKit is the framework that you'll find yourself use most often when developing iOS applications. It defines the core components of an iOS application, from labels and buttons to table views and navigation controllers. In this article, not only will we start our exploration of the UIKit framework, we will also explore the internals of an iOS project and the basic building blocks of iOS applications.


What is the UIKit framework?

While the Foundation framework defines classes, protocols, and functions for both iOS and OS X development, the UIKit framework is exclusively geared towards iOS development. It's the equivalent of the Application Kit or AppKit framework for OS X development.

Like Foundation, UIKit defines classes, protocols, functions, data types, and constants. It also adds additional functionality to various Foundation classes, such as NSObject, NSString, and NSValue through the use of Objective-C categories.

Objective-C categories are a convenient way to add extra methods to existing classes without the need for subclassing. Read this tutorial by Aaron Crabtree if you want to learn more about Objective-C categories.

Instead of exploring the key classes of UIKit as we did for the Foundation framework, we will create and journey through a new iOS project and explore the classes we encounter. By taking this approach, it will quickly become clear in what context a class is used and how each class fits in the broader scheme of an iOS application and what role it plays.


A New Beginning

Launch Xcode and create a new project by selecting New > Project... from the File menu. In the iOS section on the left, select the Application category. From the list of project templates, choose the Single View Application template.

The Single View Application template contains the basic building blocks of an iOS application and is therefore a good place to start our journey.

Name the project UIKit and enter an organization name and company identifier. Enter a class prefix, as I explained earlier in this series, and set Devices to iPhone.

Tell Xcode where you want to save the new project and make sure to put the project under version control by checking the checkbox labeled Create git repository on My Mac. Revisit this article for more information about version control and its benefits.


Files and Folders

We have learned quite a few new things since the last time we created an iOS project from scratch so it's a good idea to explore the various files and folders of our new project to see if they ring a bell.

In the Project Navigator, you should see three folders at the root of the project;

  • Products
  • Frameworks
  • a folder with your project's name, UIKit in this example
  • a folder whose name ends with TestsUIKitTests in this example

Let's take a look at the contents of each of these folders.

Products

The Products folder currently contains two items. The first item bears the name of our project and has an extension of .app. The name of the second item ends in Tests and has an extension of .xctest. I won't cover unit tests in this series, so you can ignore the second item for now.

The Products folder contains the application—or applications—created by the project after compilation of the source code.

Have you noticed that UIKit.app is highlighted in red? Whenever Xcode is unable to locate a file, it highlights the file in red. Because the project hasn't been compiled yet, Xcode hasn't created the product yet.

Frameworks

The Frameworks folder contains the frameworks your project is linked against. In the previous article, our project was only linked against the Foundation framework. This project, however, is based on an iOS application template and therefore linked against four frameworks, Foundation, UIKit, Core Graphics, and XCTest.

You may remember the Core Graphics framework from earlier in this series. The framework contains the interfaces for the (Quartz) 2D drawing API. The XCTest framework is related to unit testing, which I won't cover in this series.

There is one other location in our project that specifies which frameworks the project is linked against. Select your project in the Project Navigator, choose the only item in the Targets section on the left, and open the Build Phases tab at the top.

By opening the Link Binary with Libraries drawer, you are presented with the same list of frameworks that we saw in the Frameworks folder. Linking our project against another iOS system framework is as easy as clicking the plus button at the bottom of the list and selecting a framework from the list.

Project Folder

Most of your time is spent in the project folder, which currently contains six files and one folder named Supporting Files. Let's start by taking a look at the contents of the Supporting Files folder.

  • <PROJECT>-Info.plist: This file, commonly referred to as the "info-dot-plist" file of a project, is a property list that contains various configuration settings. Most of these settings can also be modified by selecting the project in the Project Navigator, choosing the target in the Targets list, and opening the GeneralCapabilities, and Info tabs.
  • InfoPlist.strings: If Info.plist contains values that need to be localized, then you can do so by specifying them in InfoPlist.strings. Application localization is something we won't cover in this series.
  • main.m: This file should be familiar by now. When creating iOS applications, however, you will rarely modify the contents of main.m. It contains the application's main function, which is where all the magic starts. Even though we won't be modifying main.m, it is essential for your iOS application.
  • <PROJECT>-Prefix.pch: This is the project's precompiled header file, which we already encountered earlier in this series. As its name implies, the header files listed in the precompiled header file are precompiled by Xcode, which brings down the time it takes to compile your project. The Foundation and UIKit frameworks don't change very often so there's no need to compile them every time you compile your project. In addition to precompiling the header files listed in the precompiled header file, each source file in your project is prefixed with the listed header files.

Application Components

Now that we know what the different files and folders in our project are for, it's time to explore the different components of an iOS application. As we continue our journey, we will come across several classes that belong to UIKit. Each class that belongs to the UIKit framework starts with the class prefix UI. Remember that Foundation classes are prefixed with NS.


The Model-View-Controller Pattern

Before we start exploring the UIKit framework, I want to talk about the Model-View-Controller (MVC) pattern. The MVC pattern is one of the most widespread patterns in object oriented programming. It promotes code reusability and has close ties with the concept of separation of responsibilities or concerns. One of the main objectives of the MVC pattern is the separation of an application's business logic from the presentation layer.

Cocoa Touch embraces the MVC pattern and it's therefore important to understand what it is and how it works. In other words, by understanding the MVC pattern, it will be much easier to grasp how the different components of an iOS application work together.

In the MVC pattern, a model is in control of the business logic of an application. Interacting with a database, for example, is the responsibility of the model. The view presents the data that is managed by the model to the user. The view manages the user interface and user input.

The controller is the glue between the model and the view. While the model and the view don't know about each other's existence, the controller knows about both the model and the view.

Because the controller knows about both model and view, it's often the least reusable piece of an application. The less an object knows about its environment and the objects it interacts with, the higher its reusability will be in future projects.


UIApplication

Even though the UIApplication class is a key component of every iOS application, you won't interact with it very often and you will rarely, if ever, feel the need to subclass UIApplication.

When an application launches, a singleton of this class is created. Do you remember what a singleton object is? It means that only one object instance of the UIApplication class is created during an application's lifetime.

The UIApplication instance is the entry point for user interaction and it dispatches events to the appropriate target objects. The exact meaning of this will become clear in a few minutes when we take a look at view controllers.

In most iOS applications, the UIApplication instance has a delegate object associated with it. Whenever you create an iOS project using one of the provided templates, Xcode will create an application delegate class for you. Take a look at the names of the source files in the project folder in the Project Navigator. The first two files are named TSPAppDelegate.

The instance of this class is the delegate of the UIApplication singleton. Before taking a closer look at the TSPAppDelegate class, we need to understand what the delegate pattern is.

Ole Begemann wrote an excellent article about the launch sequence of a typical iOS application. In this article, he talks about the various components involved and their role during the application launch sequence. I highly recommend reading this article if you want to get a better understanding of the role of the UIApplication class as well as the mysterious main() function in main.m.


The Delegate Pattern

The delegate pattern is used extensively in Cocoa and Cocoa Touch. In the next article of this series, in which we explore the ins and outs of a table view, you'll discover that table views rely heavily on the delegate (and data source) pattern.

Like the MVC pattern, delegation is common in object oriented programming. The delegate pattern in Cocoa Touch, however, is slightly different, because it makes use of a delegate protocol to define the behavior of the delegate object.

Let's jump ahead and take a look at table views. If you've spent any amount of time with an iPhone or iPad, then the UITableView class should be familiar to you. It presents an ordered list of data to the user and it does this job very well.

How does a table view know what to do when a row is tapped? Is this behavior included in the UITableView class? Certainly not, because this behavior varies from application to application. If we were to include this behavior in the UITableView class, it would not be very reusable.

The table view outsources this responsibility to a delegate object. Put differently, it delegates this task to another object, a delegate object. Take a moment to inspect the class reference of the UITableView class. It has two properties named dataSource and delegate. The delegate is notified by the table view whenever a user taps a row. It is the responsibility of the delegate object to respond to the user's tap.

The data source of the table view is similar in terms of behavior. The main difference is that the table view asks the data source object for something, the data that it needs to display.

Delegate and data source objects, such as the table view's delegate and dataSource objects, are almost always custom classes, classes that you create, because their implementation is application specific.

Before we take a look at the TSPAppDelegate class, it's important to understand that a delegate object conforms to a delegate protocol. In the previous article, we already learned about protocols in Objective-C and how they define behavior by defining a list of methods for its adopters to implement.


The Application Delegate

Now that we know what delegation is, it's time to explore the TSPAppDelegate class that Xcode created for us. At application launch, the application creates an instance of the TSPAppDelegate class. You typically never need to explicitly instantiate an application delegate object.

Open the header file of the TSPAppDelegate class (TSPAppDelegate.h) to examine its contents. If we ignore the comments at the top, the first line imports the header files of the UIKit framework so we can work with its classes and protocols.

#import <UIKit/UIKit.h>

The next line should be familiar. This is the start of the interface of the TSPAppDelegate class as denoted by the @interface directive. It specifies the name of the class and the class's superclass, UIResponder.

Between angle brackets are the protocols the class conforms to. The TSPAppDelegate class conforms to one protocol, the UIApplicationDelegate protocol.

@interface TSPAppDelegate : UIResponder <UIApplicationDelegate>

The next line is a property declaration, which should look familiar. The property, window, is an instance of UIWindow, which is a subclass of UIView. The words between parentheses, strong and nonatomic, are optional property attributes that specify the storage semantics and behavior of the property. You can ignore them for now.

@property (strong, nonatomic) UIWindow *window;

The most interesting part of the interface of the TSPAppDelegate class is the UIApplicationDelegate protocol. Take a look at the reference of the UIApplicationDelegate protocol for a complete list of the methods the protocol defines.

The protocol defines dozens of methods and I encourage you to explore a few of them to get an idea of the protocol's capabilities. The method that's most interesting to us at this point is application:didFinishLaunchingWithOptions:.

When the UIApplication instance has finished preparing the application for launch, it will notify the delegate, our TSPAppDelegate instance, that the application will finish launching—but that it hasn't yet.

Why does it notify the application delegate of this event? The UIApplication instance notifies its delegate about this event so that it has an opportunity to prepare for application launch. Head over to the implementation file of TSPAppDelegate to see what I mean. The first method in the implementation file is application:didFinishLaunchingWithOptions: and it should more or less look like the one pasted below.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    return YES;
}

The application:didFinishLaunchingWithOptions: method provides a reference to the UIApplication instance and a dictionary with options, which are of no interest to us at this point. The method's implementation is pretty simple. All it does is return YES to tell the UIApplication instance that the application is ready to launch.

Storyboard

The Xcode project contains another interesting file, Main.storyboard. The storyboard defines how the user interface of our application will look like. By default, the storyboard is named Main.storyboard. Select the storyboard to open it.

The storyboard currently contains one view in the central workspace. On the right of the Project Navigator you can see a list of items, which are the objects you see in the view. The top item is named View Controller Scene, which contains one child item labeled View Controller.

The View Controller object also has a number of child items, but there is one that is of special interest to us, the object named View. Remember our discussion about the MVC pattern. Here you can see the MVC pattern in action. The model is missing at the moment, but we do have a view, the View object, and a controller, the View Controller object.

When our application launches, the storyboard is used to create the application's user interface. The view controller is automatically instantiated and so is the view controller's view. The View object in the storyboard is managed by the view controller.

Wait a minute. Where can I find the class of the view controller in the storyboard? How can I change its behavior to create a unique application? Select the View Controller object on the left in the storyboard and open the Identity Inspector on the right.

The Identity Inspector tells you everything you need to know. At the top, in the section Custom Class, you can see the name of the view controller's class, TSPViewController. Have you noticed that the two files we haven't talked about yet have that same name? We'll explore these files in a few moments.

The view controller is instantiated for us, because it is the initial view controller of the storyboard. This is indicated in the storyboard by the arrow pointing to the storyboard.

UIViewController

If you open TSPViewController.h, you'll notice that the TSPViewController class is a subclass of UIViewController. Like TSPAppDelegate, the UIViewController class is a subclass of UIResponder. View controllers, or subclasses thereof, fall in the controller category of the MVC pattern. As the name implies, they control a view, an instance of the UIView class, which falls in the view category of the MVC pattern.

A view controller manages a view and the view's subviews as we'll see later. To do this, the view controller needs to know about the view. In other words, it needs to have a reference to the view.

The view controller in the storyboard has a reference to the view. You can verify this by selecting the view controller in the storyboard and opening the Connections Inspector on the right.

In the Connections Inspector, you should see a section named Outlets. The term outlet is a fancy word for a property, which you can set in the storyboard. Hover with your mouse over the outlet named view and observe how the view in the workspace is highlighted. That is the connection between the view controller and the view.


UIView

Even though your application can have only one instance of UIWindow, it can have many views. The UIView class is an important component of the UIKit framework, because many classes inherit from it—either directly or indirectly.

Revisit Main.storyboard by selecting it and take a look at the Object Library at the bottom of the Inspector.

Browse the Object Library and drag a label and a button to the view in the workspace. It doesn't matter where you position them in the view as long as they are in the view controller's view.

You'll have noticed that two new objects have been added to the Objects section on the left. Both the label (UILabel) and the button (UIButton) inherit from UIView. Did you notice that the Label and Button objects are slightly indented compared to the View object? This indicates that the Label and Button objects are subviews of the View object. A view can have one or more subviews that it manages.

As I mentioned earlier, the UIView class is an important component of UIKit. A view manages a rectangular area or frame on the screen. It manages the contents of the area, the subviews, and any interactions with the view's contents. The UIView class is a subclass of UIResponder. You'll learn much more about views over the course of this series.


Outlets

Let's take a look at an example to illustrate the relationship between the storyboard, the view it contains, and the view controller. These three components are important and I want to make sure that you understand just how they work together.

A few minutes ago, you added a label and a button to the view controller's view. How does the view controller know about these objects? At the moment, they don't appear in the Connections Inspector, but we can change that by telling the view controller about them.

Open the view controller's header file (TPSViewController.h) and add a property for the label and for the button.

@property IBOutlet UILabel *myLabel;
@property IBOutlet UIButton *myButton;

By adding the IBOutlet keyword to the property declaration, the properties will appear in the Connections Inspector in the storyboard and that is what we want.

Head back to the storyboard, select the View Controller object in the View Controller Scene, and open the Connections Inspector on the right. The new properties are now listed in the list of Outlets. However, the view controller hasn't yet made the connection between the new properties and the objects in the storyboard.

This is easy to remedy. Drag from the empty circle on the left of the myLabel outlet to the label in the workspace. This will create that all-important connection so that the view controller knows about the label. Do the same for the button.


Even though we can change the text of the label in the storyboard, let's do this in the view controller to illustrate that the view controller has access to the label and button in the storyboard.

Open the view controller's implementation file (TPSViewController.m) and look for the viewDidLoad method. Modify the viewDidLoad method to reflect the implementation below. The comments have been omitted for clarity.

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self.myLabel setText:@"This is an instance of UILabel."];
}

We can send messages to the label property by asking the view controller, self, for its myLabel property. By sending the myLabel property a message of setText: and passing a string literal, we update the label's text.

Note that setText: is an accessor or setter. Even though it's possible to use Objective-C's dot notation (see below), I've used the more traditional syntax as it better shows you what's actually happening.

self.myLabel.text = @"This is an instance of UILabel";

Run your application in the iOS Simulator by clicking the Run button in the top left and notice that the label's text is indeed updated.


Actions

We've explored a lot of new things in this article. I want to end this installment by talking about actions. Just like outlets, actions are nothing more than methods that you can see in the storyboard.

Let's see how this works. Open the view controller's header file (TPSViewController.h) and add the following method declaration somewhere in the view controller's interface block.

- (IBAction)changeColor:(id)sender;

Don't be confused by the IBAction keyword. IBAction is identical to void, which means that the method returns no value. If we take a closer look at the method declaration, we can see that it takes one argument of type id, a reference to an Objective-C object.

As the argument name implies, the argument of the method or action is the object that sent the message to the view controller. I will explain this in more detail in just a bit.

Revisit the storyboard, select the View Controller object in the View Controller Scene, and open the Connections Inspector. A new section has appeared in the Connections Inspector named Received Actions and the action we just added is listed in this section.

Drag from the empty circle on the left of the action to the button in the workspace. A small window with a list of options should appear. The list contains all the possible events that the button can respond to. The one that interests us is Touch Up Inside. This event is triggered when a user touches the button and lifts their finger while still inside the button.

Build and run your application once again and tap the button. Did the application crash for you as well? How did this happen? When you tapped the button, it sent a message of changeColor: to the view controller. Even though the view controller declares a changeColor: method, it does not implement this method yet.

Whenever a message is sent to an object that does not implement a corresponding method, an exception is raised and the application crashes if the exception isn't caught. You can verify this by running the application once more, tapping the button, and inspecting the output in the console window.

To remedy this, we need to implement the changeColor: method. Open the view controller's implementation file (TPSViewController.m) and add the following method implementation somewhere in the implementation block.

- (IBAction)changeColor:(id)sender {
    NSLog(@"Sender Class > %@", [sender class]);
    NSLog(@"Sender Superclass > %@", [sender superclass]);

    int r = arc4random() % 255;
    int g = arc4random() % 255;
    int b = arc4random() % 255;

    UIColor *color = [UIColor colorWithRed:(r/255.0) green:(g/255.0) blue:(b/255.0) alpha:1.0];

    [self.view setBackgroundColor:color];
}

The implementation of the changeColor: method is identical to the one we used earlier in this series. However, I've added two extra NSLog calls to its implementation to show you that the sender of the message is indeed the button that we added to the storyboard.

The method itself is pretty simple. We generate three random integers between 0 and 255, pass these values to colorWithRed:green:blue:alpha: to generate a random color, and update the background color of the view controller's view with the randomly generated color.

Note that self.view references the view that the view controller manages and that we saw earlier in the storyboard.

Build and run your application one more time, tap the button, and don't forget to inspect the output in Xcode's console window. You'll notice that the sender is an instance of UIButton and its superclass is UIControl.


Conclusion

In this article, we've explored a few classes of the UIKit framework and we took a close look at the various components of an iOS application. We'll explore and work with the UIKit framework in more detail in the rest of this series.

If you don't fully understand the various concepts and patterns, then I'm sure that you will as the series progresses. Don't hesitate to leave a comment if you have question about this article.

Advertisement