Showing posts with label Swift. Show all posts
Showing posts with label Swift. Show all posts

Networking in Swift: Building a RESTful API in PHP, Part 1

This is the second post in our tutorial series on networking in Swift. If you followed along in the introductory article, you have installed MAMP on your local machine, created an .htaccess file and set up the basic file structure for the project. In this tutorial, we'll begin building the API for our Super PHPlumbing Bros web service.

This RESTful API in PHP will serve content to the Swift-based iOS client application we'll create in the final part of the series. Our API will perform five distinct tasks when queried. It will provide: 1) inventory items response logic for our Plumbing Tools; 2) inventory items response logic for Plumbing Supplies; 3) inventory item response logic for Plumbing Tool with Description; 4) Inventory item response logic for Plumbing Supply with Description; 5) Error response logic.

In this article, we will cover the structure of our API queries, provide a simple bare bones interface for the service, and then build the first half of our custom API to serve up our plumbing supplies inventory.

API Queries
Our application will communicate with the web api through a simple url scheme. If you are not familiar with url schemes, take a brief detour through the linked Wikipedia page to learn about how they work (simply memorizing the components of a url scheme outright will save you lots of needless lookups later).

Our first stab at a url scheme looks crude. Here is the URL scheme that we will use to access our entire inventory of plumbing tools: http://localhost:8888/v1/PlumbingAPI.php?method=copper_pipes_and_fittings&format=json.

Let's take a closer look at this scheme. Any text in a URL that comes after the question mark (?) is known as the URL query component. Each key/value pair that follows is logically separated by an ampersand (&). In this example the query string contains two key/value pairs. These key/value pairs will get passed along to our PlumbingAPI.php script via an associative array known as $_GET[]. Within our PHP script we will access the values for the 'method' and 'format' keys as follows: $_GET['method'] and $_GET['format'] would return 'copper_pipes_and_fittings' and 'json', respectively, in the crude example above. We use these values to determine what was requested of our API.

A Bare Bones API
Let's get down to it. Using your text editor, open PlumbingAPI.php for both versioning folders, v1 and v2. Until further noted, we'll be entering the same code in both versions. For the skeletal structure of our API, we are going to adapt the code from Mark Roland's helpful tutorial on "How to Build a RESTful API Web Service in PHP." We'll explain each component as we add flesh to our bare-bones script. Here's a Gist of the script:


After reading through the code, copy it into the PlumbingAPI.php file in your v1 folder. Using the URL scheme from above, point your web browser at http://localhost:8888/v1/PlumbingAPI.php?method=copper_pipes_and_fittings&format=json, and you will see the API's response to the given method and format:

Simple API call to bare bones script


If you now navigate to http://localhost:8888/v1/PlumbingAPI.php?method=plumbing_tools&format=json, you'll see the response from the plumbing_tools method:

Second API call to bare bones script
  
If this is not working for you, then go back and make sure that you followed all the steps. If you do see a response in your web browser, then congratulations! You've successfully built and deployed your locally hosted web service. The various responses from our api are made possible by the following conditional code structure, from line 120 to the end of the file above:
// Copper Pipes and Fittings API //
if( strcasecmp($_GET['method'],'copper_pipes_and_fittings') == 0){
    echo 'Copper Pipes and Fittings API Call. <br>';
}

// Plumbing Tools API //
else if( strcasecmp($_GET['method'],'plumbing_tools') == 0){
    echo 'Plumbing Tools API Call. <br>';
}

// ** Deliver Response ** //
// Return Response to browser //
deliver_response($_GET['format'], $response);
With the exception of the function definitions, our script is executed from top to bottom. Notice the conditional if else if structure here. In our first API call we passed in the value 'copper_pipes_and_fittings' for the 'method' key. Recall that the parameters of a query string are passed in to the $_GET[] global array, which we read from in our first conditional if check. Since it evaluates to true in the first API call, we fall in that conditional block and therefore echo "Copper Pipes and Fittings API Call", followed by the function call: deliver_response($_GET['format'], $response). This last function call is what prints out the second line in the browser.

In our second api call, we passed in the value 'plumbing_tools' for the 'method' key in the URL. With this query, we fell into the conditional else-if check above. This gave us our alternate response. That's all there is to it!

Moving forward, we'll build on top of this primitive structure of conditional checks followed with a response using the echo call.  For explanations of built-in methods such as  strcasecmp() and echo, check out php.net and search for those calls to get documentation along with code samples on how to use them.

Building the Supplies Interface
We'll now begin building out the control flow for the various tasks our API will perform. In the first if conditional control flow replace the code at line 122 (echo 'Copper Pipes and Fittings API Call. <br>';) with the following:
// build payload //
$response['code'] = 1;
$response['api_version'] = '1.0.0';
$response['status'] = $api_response_code[ $response['code'] ]['HTTP Response'];
   
// if an 'item_id' was provided then return details for that item //
if ( $_GET['item_id'] ) {
    $response['item_id'] = strtoupper($_GET['item_id']);
    $response['data'] = copper_pipe_or_fitting_item_details(strtoupper($_GET['item_id']));
}
// else return our entire inventory of copper pipes and fittings //
else {
    $response['data'] = copper_pipes_and_fittings_inventory_without_description();
}
Save your PlumbingAPI.php file and point your browser to this URL: http://localhost:8888/v1/PlumbingAPI.php?method=copper_pipes_and_fittings&format=json. The response will appear as follows in your web browser:
Copper Pipes and Fittings Inventory without Descriptions.
Copper Pipes and Fittings Inventory.
Delivering Response. $api_response = Array, format = json
Your are seeing this response because our first if check did not fall through as we did not provide an 'item_id' key with an associated value pair as parameters in the query part of our URL. In other words, a parameter with this format, '&item_id=<some item id>', was not appended to the above URL. This resulted in our conditional control flow to fall through the else path. In this else block we call a method that we defined earlier: copper_pipes_and_fittings_inventory_without_description(). In our definition of this method, notice that we call another method: copper_pipes_and_fittings_inventory(). This last method is responsible for fetching our entire inventory of copper pipes and fittings along with all item details. Go to this method, found in lines 27 -33 above, and replace line 32 (echo 'Copper Pipes and Fittings Inventory. <br>';)<code> with the following:


This is an associative array of sub-arrays. Each sub-array contains all the information of one inventory item. There are twelve items in our hypothetical Copper Pipes and Fittings category, the information for which was cobbled together from online sources. In a real world scenario, this or a similar method would normally pull this data from a data store like a database. But for the sake of brevity we will skip this part. Now go to where we defined the method copper_pipes_and_fittings_inventory_without_description() (line 56 in the bare bones files above), and replace lines 57 and 58 with the following: 
return copper_pipes_and_fittings_inventory();
For now we'll simply return our entire inventory with descriptions. We will revisit this method later and write code to omit item descriptions. Now navigate to our response delivery function (function deliver_response($format, $api_response)), line 23 in the bare bones code, and replace its echo command in line 24 with the following:


The response to our API query gets processed here. If a parameter of 'format=json' is provided in the query part of the URL, then our script would fall through our first if check. This parameter informs our API that one of three available formatted responses was requested. We support three formats in this example: json, xml and html. 

Let's now write the code to process json format requests. In the first conditional if-check block (line 14) replace the comment (// JSON Response //) with the following code:
// Set HTTP Response Content Type //
header('Content-Type: application/json; charset=utf-8');

// Format data into a JSON response //
$json_response = json_encode($api_response, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);

// Deliver formatted data //
echo $json_response;
Save your PlumbingAPI.php file and point your browser to this url, http://localhost:8888/v1/PlumbingAPI.php?method=copper_pipes_and_fittings&format=json. The response will appear as follows in your web browser:
{
    "code": 1,
    "status": 200,
    "data": [
        {
            "id": "CP12010",
            "name": "1 inch copper pipe.",
            "image": "http://localhost:8888/assets/1_inch_copper_pipe.png",
            "description": "1 in. x 10 ft. Copper Type M Hard Temper Straight Pipe for a multitude of plumbing and heating purposes. It is NSF and ANSI Standard 61 certified. Made of hard-temper ASTM - B88 copper. For general plumbing and heating purposes. Alloy C12200 (DHP) meets industry standards and is NSF and ANSI Standard 61 certified. Meets or exceeds industry standards to deliver a high quality flow product. Plumbing and mechanical codes govern what types of products may be used for applications. Local codes should always be consulted for minimum requirements"
        },
        {
            "id": "CP12020",
            "name": "1 1/4 inch copper pipe.",
            "image": "http://localhost:8888/assets/1_1_4_inch_copper_pipe.png",
            "description": "1 1/4 in. x 10 ft. Copper Type M Hard Temper Straight Pipe for a multitude of plumbing and heating purposes. It is NSF and ANSI Standard 61 certified. Made of hard-temper ASTM - B88 copper. For general plumbing and heating purposes. Alloy C12200 (DHP) meets industry standards and is NSF and ANSI Standard 61 certified. Meets or exceeds industry standards to deliver a high quality flow product. Plumbing and mechanical codes govern what types of products may be used for applications. Local codes should always be consulted for minimum requirements"
        },
    .
    .
    .
    .
        {
            "id": "CP14040",
            "name": "1 1/2 inch copper elbow fitting.",
            "image": "http://localhost:8888/assets/1_1_2_inch_copper_elbow_fitting.png",
            "description": "1 1/3 in. Copper Type M Hard Temper Straight Pipe for a multitude of plumbing and heating purposes. It is NSF and ANSI Standard 61 certified. Made of hard-temper ASTM - B88 copper. For general plumbing and heating purposes. Alloy C12200 (DHP) meets industry standards and is NSF and ANSI Standard 61 certified. Meets or exceeds industry standards to deliver a high quality flow product. Plumbing and mechanical codes govern what types of products may be used for applications. Local codes should always be consulted for minimum requirements"
        }
    ],
    "api_version": "1.0.0"
}
The vertical ellipses indicate that we trimmed the actual response. You should see a lot more data in your browser. The problem with this response is that the copper pipes and fittings inventory response contains too much data. In our next step we'll trim the response so that item descriptions are omitted. 

It is not good practice to submit details of items when requesting them in bulk. In a real-world scenario, internet access is often spotty and unreliable. And serving up too much data could negatively impact your users' experience. And since users are often not aware that your application is not to blame for a given issue, but rather their connectivity to the network, they will associate this bad experience with your application. So, in an effort to mitigate connectivity issues, we should always prefer to send the least amount of data as possible over a network. Also, it is very unlikely that you can fit all this data for one item onto a screen when presenting the user with a list of items.

To omit item details, navigate to where we defined the method copper_pipes_and_fittings_inventory_without_description(), and replace our return command (return copper_pipes_and_fittings_inventory();) with this chunk of code:
    // pull our entire inventory of copper pipes and fittings //
    $inventory = copper_pipes_and_fittings_inventory();
   
    // container for inventory minus descriptions//
    $inventory_without_details = array();
   
    // iterate through inventory and duplicate all attributes except descriptions //
    foreach ($inventory as $key=>$value) {
        if (is_array($value)) {
            $inventory_item = array();
            foreach ($value as $subkey=>$subvalue) {
                if ( strcasecmp($subkey,'description') != 0 )
                    $inventory_item[$subkey] = $subvalue;
            }
            $inventory_without_details[$key] = $inventory_item;
        }
    }
    return $inventory_without_details;    
This code is straight forward. It iterates through the json objects and all the items into another container with the exception of key value pairs that are associated with a key name of 'description.' Save your PlumbingAPI.php file and point your browser to this url, http://localhost:8888/v1/PlumbingAPI.php?method=copper_pipes_and_fittings&format=json. The response will appear as follows in your web browser:
{
    "code": 1,
    "status": 200,
    "data": [
        {
            "id": "CP12010",
            "name": "1 inch copper pipe.",
            "image": "http://localhost:8888/assets/1_inch_copper_pipe.png"
        },
        {
            "id": "CP12020",
            "name": "1 1/4 inch copper pipe.",
            "image": "http://localhost:8888/assets/1_1_4_inch_copper_pipe.png"
        },
          .
    .
    .
    .
        {
            "id": "CP14040",
            "name": "1 1/2 inch copper elbow fitting.",
            "image": "http://localhost:8888/assets/1_1_2_inch_copper_elbow_fitting.png"
        }
    ],
    "api_version": "1.0.0"
}
Again, the vertical ellipses indicate that we trimmed the actual response. Notice that the descriptions have been omitted from the response. 

We will now write code to serve an individual copper pipe or fitting with a description. Find where the method function copper_pipe_or_fitting_item_details($item_id) is defined (line 66 in our bare bones API) and replace the two lines filling out the function (i.e. 67 and 68), with the following:
// pull our entire inventory of copper pipes and fittings //
$inventory = copper_pipes_and_fittings_inventory();
   
// container for item matching the provided item_id //
$inventory_item = array();
   
// iterate through our inventory and find the requested item //
foreach ($inventory as $key=>$value) {
    if (is_array($value) && strcasecmp($value['id'], $item_id) == 0) {
        foreach ($value as $subkey=>$subvalue) {
                $inventory_item[$subkey] = $subvalue;
        }
        break;
    }
}
return $inventory_item;
Save your php file and point your browser to this URL: http://localhost:8888/v1/PlumbingAPI.php?method=copper_pipes_and_fittings&item_id=CP12010&format=json. This is an endpoint to the first item from our json inventory response above. You should see the response below:
{
    "code": 1,
    "status": 200,
    "data": {
        "id": "CP12010",
        "name": "1 inch copper pipe.",
        "image": "http://localhost:8888/assets/1_inch_copper_pipe.png",
        "description": "1 in. x 10 ft. Copper Type M Hard Temper Straight Pipe for a multitude of plumbing and heating purposes. It is NSF and ANSI Standard 61 certified. Made of hard-temper ASTM - B88 copper. For general plumbing and heating purposes. Alloy C12200 (DHP) meets industry standards and is NSF and ANSI Standard 61 certified. Meets or exceeds industry standards to deliver a high quality flow product. Plumbing and mechanical codes govern what types of products may be used for applications. Local codes should always be consulted for minimum requirements"
    },
    "api_version": "1.0.0",
    "item_id": "CP12010"
}

Congratulations! We have completed the first half of our web API, serving up content for our copper pipes and fittings inventory. In the next article in the series, we'll complete the API to serve up our inventory of plumbing tools, and then begin building our Swift application to bring that content to our end user. Follow the line for part two on building a RESTful API in PHP.

This project can be found on GitHub.

As always, comments, questions, and suggestions are welcome below!

Index
Introduction
Introduction and Overview: From the Back End API to the End User Application

The Web API
Building a RESTful API in PHP, Part 1
Building a RESTful API in PHP, Part 2

The Swift Client App
Networking in Swift: Building the Swift Client, Part 1
Networking in Swift: Building the Swift Client, Part 2
Networking in Swift: Building the Swift Client, Part 3
Networking in Swift: Building the Swift Client, Part 4
Networking in Swift: Building the Swift Client, Part 5


This tutorial was authored by Stefan Agapie, a Senior iOS Software Engineer, and adapted for the present piece. 

Networking in Swift: From the Backend API to the End User App

Introduction
In this tutorial series, we will create an iOS application that will leverage Swift's networking layer to query a custom-built web service. First, we'll build a RESTful API in PHP from the bottom up and host it on our local machine. Then we'll craft an iOS Swift application to consume the content provided by the service, and present it to the end user in a collection view. The series is intended for people who have some degree of programming experience, but who have not yet obtained much practical knowhow on building an everyday, real-world, user-facing, mobile application. 

A typical use case for mobile applications requires the consumption of content that is hosted on a web server. For successful mobile app development, this means that you not only need to know how to build an application that consumes web content, but also to have a high level understanding (at the very least!) of how a web service actually delivers content to your mobile application.

This is important because you will encounter network related errors during your development cycle. And if you don't have at least a basic understanding of the web service that your are trying to communicate with, then you cannot be sure where the errors are originating from. In addition, you will likely also be asked, at work or by your own clients, to begin writing a mobile application that relies on a web service that has not been built yet! (This actually happens way too often!) In such cases, you can write your own temporary web service that delivers mock data to your application, if you know how to build one. Although there are other ways of delivering such mock data, this can be just as useful. 

In this article, we'll provide an overview of the project, and then work through the preliminary steps for running the web service on our local machine. In the following articles, we'll build out the PHP script that will execute the API, and finally construct our Swift application to query the service and return the relevant data to the end user.

The ABCs of APIs
What is an API and how will our Swift application interface with it? API stands for Application Programming Interface. A simple web search for 'API' will return many definitions with various types of descriptions and creative examples. I like to think of an API as a real object. 
Source

Since the internet is a series of pipes and tubes, our API will provide an interface to a plumbing supply inventory. Let's call our API the Mario Interface. Mario works at the front desk of a plumbing supply house called Super PHPlumbing Bros Inc. Mr. Swift is a plumber who needs some supplies to rescue a local potentate's daughter from the clutches of an invading warlord.

Mr. Swift finds PHPlumbing and walks up to the counter where he encounters Mario. Mr. Swift tells Mario that he would like some piping, mushrooms and a wrench. Mario says, "No problem, but first I need you to know exactly what you need," and hands Mr. Swift two forms.

Each form is titled with the company's name. Below the title, there are several check boxes, but only one may be checked per form. The relevant check boxes are: Piping/Fittings and Plumbing Tools. Below that is a description field for the requested items along with their quantity. 

Once completed, Mr. Swift hands the forms to Mario, who then passes them along to his employees, local Toads from the Mushroom Kingdom, who are tasked to assist him. The Toads find the relevant items, bring them out and place them on the counter. 

If at any point during this process there was a problem retrieving Mr. Swift's supplies, the Toads are responsible for reporting these errors up the chain of command, from the assistants up to Mario and terminating at Mr. Swift.

In our analogy, Mr. Swift is the client (our iOS application) in need of content or plumbing supplies. Super PHPlumbing Bros Inc. is the store or website that has the supplies or content that Mr. Swift is looking for. The form for getting supplies is the actual url (location of content) that is used to find and retrieve the content. And Mario, along with the Toads, comprise the API. 

APIs, and people like Mario, are needed to maintain a system of flow control structures that are necessary to efficiently run the business logic of the operation. Can you imagine a plumbing supply house that had no control structures like forms and employees to manage its everyday workflow? The princess would be doomed.

In this tutorial series, we'll construct a RESTful API in PHP to serve up an inventory of plumbing tools and supplies, and then build a custom Swift app to interface with the API and serve that inventory to the end user. For now, let's get our local server up and running. 

Setting Up the Local Server
Unfortunately, the PHP file that will serve our API will not execute on its own. A service is required to interpret and execute our PHP script. We therefore need to set up a place on our local machine to host our Super PHPlumbing Bros. supply house. One of the easiest ways to get a server up and running on a Mac is with MAMP. Once you've downloaded MAMP, you can run the package by double clicking it.

After the package mounts, follow the instructions to install the software. 

Once installed, navigate to your Applications folder and start MAMP. You will be prompted with several initialization screens. Once MAMP is installed, start the server my clicking the START button in the top right corner of the application window. 


The tiny box to the right of the word Apache should turn green if everything went smoothly. This means that your server is up and running! Now start a new session of Safari, and in the url field type the following address: http://localhost:8888 You should see a similar screen to the following, which indicates that all is in working order:

.htaccess
A .htaccess file provides directory level configuration on how a web server handles requests to resources that are in the same directory as the .htaccess file itself. Note that using .htaccess is discouraged for production environments, but for the purposes of our tutorial, it should work just fine. Using your favorite text editor, create a new file and name it .htaccess. In the screen capture above, notice the directory path next to the text, “Document root:”. Mine reads: "Document root: /Applications/MAMP/htdocs." This is where your PHP file, along with all related resources will live. Place your .htaccess file in this folder.

Remember, any file name that begins with a period “.” is a system file and is hidden by default. To view hidden files, you can use the "ls -a" command in a terminal. To view hidden files in Finder, you can follow the instructions here.

File Structure 
Navigate to the folder that contains your .htaccess file. For me, it's /Applications/MAMP/htdocs, and create three folders with the following names: v1, v2, assets. More on these folders later, but for now, your folder structure should more or less look like the following:

Using your text editor create a new file and call it PlumbingAPI.php. This file models the Mario Interface, our counter guy. Place a single copy in folder v1 and v2. The v1 and v2 folder will be used for version control. The earlier versions of an API would typically reside in folders with a smaller number while the most recent API edition would live in the folder with the largest number.

Moving Forward  
With that, we're all set to go! In the next segment of the tutorial we'll build our RESTful API in PHP, so let's take the plunge. Or, if you want to skip ahead, follow the link to the tutorial segment on building our Swift client application.


Tutorial: A Simple iOS Stopwatch App in Swift

In this tutorial, we will create a single view iOS application using the Swift programming language. The tutorial will provide some insight into basic usage of the Apple Xcode integrated programming environment, as well as the model/view/controller software architectural pattern. Our target audience are people who have some prior experience in application development and programming but who are relatively new to Xcode and iOS development. The project goal is to build a simple iOS stopwatch-style timer application designed for iPhone using Swift.

The app will contain two labels (one for our title and one for our numeric timer display), and two buttons (a start/stop button, and a reset button). We will first lay out our main view, which will contain these elements and then use the interface builder (i.e. storyboard) to hook our view into the controller (IBOutlets and IBActions). Finally, we will turn to the business logic of the app. In the end, we will have two imports and a view controller. We will add three methods to the view controller class: two actions methods and one helper method. The tutorial will be broken down into a series of just over thirty steps with screen caps to provide a quick visual aid.

The first thing you'll need to do, if you haven't already, is download the latest version of Xcode 6 (currently in beta as of this writing). If you are completely new to Xcode, you may find it difficult to navigate the interface. There are tons of great guides to Xcode that can be found online such as this one.

On initial startup, Xcode will present you with its ‘Welcome’ screen and offer several options. Select the “Create a New Xcode Project” panel from the window (see figure 1). If it does not present you with this screen, select File->New->Project from the menu bar.

Figure 1
On the following screen, select “Single View Application” and press the “Next” button (see figure 2).

Figure 2

Next, choose the options for your new project (see figure 3) and fill in the necessary fields as you wish, ex. project and organization names, and select “iPhone” as the device, since we are creating an iPhone app.

Figure 3
The following screen will then prompt you to provide a destination directory for your project. I like to keep current projects in a folder on my Desktop. There is also an option on the bottom of the screen to place your project under source control. If you don’t know what source control is or how to use it, then simply uncheck this box. (However, it is highly recommended that you invest some time learning about source control systems such as git.) Click “Next” once you have made your selections.

Your project should have opened to a screen similar to the one in figure 4.

Figure 4
From the device dropdown menu, located in the upper left corner, select iPhone 5s (notice also the other options that could have been selected here if we were planning to create a different app). See figure 5.

Figure 5

Now that we have our project’s initial setup completed, let’s get down to business! From the Project Navigator, select the Main.storyboard file. See figure 6.

Figure 6
In the Storyboard, select any view, then go to the File Inspector in Xcode’s right panel. Uncheck “Use Size Classes”, and you will be asked to keep size class data for: iPhone/iPad. Then click the “Disable Size Classes” button. Doing this will make the storyboard’s view automatically size with the selected device. See figure 7.

Figure 7
In the top left corner of Xcode, locate the “Play” button and press it to build and run your project for the first time. See figure 8. Upon a successful first launch of the project, you should see something like the image in figure 9, an iOS simulator. If you get any errors and the project does not build correctly, read the error report(s) carefully and see if you can troubleshoot the problem.


From the Object Library toward the bottom of the right panel in Xcode, select Label (figure 10) and then drag and drop it at the left style guide, but vertically centered into your single storyboard scene/view. See figure 11. The style guides are temporary visual placement lines that appear as you position view elements into your scene. This label will eventually provide the numeric display of our running stopwatch.

Figure 10

Figure 11

In order to make the label wider, we will select and drag the trailing edge of our Label element to the right of your scene until it meets the right most style guide. See figure 12.

Figure 12
From the Attribute Inspector panel in the right panel of Xcode, toggle the text alignment to center so our text appears in the middle of the label. See figure 13.

Figure 13
Go back to the object library and place two Buttons equally spaced apart about midway between the label and the bottom of our scene. See figure 14. These will function as our reset button and our start/stop button on the stopwatch.

Figure 14

From the Size Inspector in Xcode’s right panel change, the width of each button to 60 points. See figure 14.1.

Figure 14.1
Run your project to see what it looks like. Again, if you get any errors and the project does not build correctly, read the error report(s) carefully and see if you can troubleshoot the problem.

Select the Assistant Editor from the top right corner of Xcode to display the storyboard and associated Swift file side-by-side. Now hide both the Navigator and Utilities panels by clicking on the appropriate panel buttons in the top right corner of Xcode. See figure 15.
Figure 15
Now let’s connect up our storyboard elements to our controller, which will connect our interface to our code, that way all the relevant interface elements can communicate events to the controller.

Place your mouse pointer over the Label; then press and hold the control button while clicking and holding down your mouse button as you pan your mouse pointer across the screen and into the right side of Xcode where your Swift file is located. You should see a blue line follow your mouse pointer. See figure 16.

Figure 16

Once in the class area, as shown, release the mouse button and the control as well.  You will see a dialogue box prompting you for the name of your outlet. Name it ‘numericDisplay’. See figure 17. This will add the necessary outlet code to your Swift controller class. An outlet is a reference pointer to an element inside your storyboard. Creating outlets allows for easy access to objects in your storyboard. After naming the outlet, your screen should look like figure 18.

Figure 17


Figure 18

Go ahead and connect the buttons as outlets as well. Name the left button ‘resetButton’ and the right button ‘startStopButton’.

In a similar fashion to the newly created outlets, we will now create action methods for each button. This time we will drag the blue line toward the bottom of the file but inside the class body. Name the left button resetButtonPressed and startStopButtonPressed for the right button. In the dialog box, make sure you select 'Action' from the Connection drop down menu. See figure 19. Action methods are the functions in your class that get messaged/called when the button that is associated with the connected method is triggered by an event. An event is initiated when the user interacts with any of your buttons.
Figure 19
Your interface should now look like the screencap in figure 20.

Figure 20

To accurately update our numeric display label, we need to tie it in to a mechanism that will update at very precise time intervals. To access this functionality, we need to import the appropriate class library. From Xcode’s menu bar, select the Window tab drop down menu then select Documentation and API Reference. See figure 21. The documentation search window should appear. In the search bar type CADisplayLink and locate the appropriate documentation. Read through the documentation and familiarize your self with the CADisplayLink class. This class is very useful when your code needs precise timing control.

Figure 21

Notice that the CADisplayLink requires the QuartzCore framework. A framework is a set of classes with predefined functionality so that you don’t have to reinvent the wheel; it's code packaged for re-use, so use it!  With Swift you no longer need to define an interface(.h) and an implementatin(.m) file to define a class which is nice. Also, when importing different frameworks into your project you no longer have to go Xcode's build setting and explicitly add that framework; it automatically loads when you use the keyword import followed by the desired framework like so: import {SomeFramework} but without the curly braces.  And my favorite addition is the fact that semicolons are no longer required! WhooHoo! There are also a ton of outher features of Swift that I have yet to discover. In your ViewController.swift file add the line of code importing QuartzCore:


Importing a framework into your file gives you access to its classes and functionality. In your ViewController class, add the following var properties just below the @IBOutlet properties. Add the code in lines 5 and 6 below:



‘var’ is short for variable and displayLink is our object pointer of type CADisplayLink. We use this pointer to hold a strong reference to an instantiated CADisplayLink object that we will create in a few moments. We want a strong reference to an instance of CADisplayLink to be able to access it throughout the various parts of our class. We also define a lastDisplayLinkTimeStamp of type CFTimeInterval. This variable will store a running tally of the total elapsed time.

Now let’s set the default view element values for our numeric display label and our two buttons. Add the code below to our viewDidLoad() method:



In your viewDidLoad() method now add the lines of code from the snippet below:



The first new line of code above (line 16) creates an instance of a CADisplayLink object, and assigns this class, i.e. “self,” as the target for messages that inform us of a display refresh rate update. This occurs in the first parameter of the CADisplayLink(<first parameter>, <second parameter>) method call. In the second parameter we pass the name of the method that we would like to be called when there is a display refresh rate update. We will define this method shortly. The second new line of code (line 9) ensures that the display link does not begin its updates until we press the Start button in our user interface. The third new line of code (line 12) schedules the display link to begin sending notifications to our instance method about display refresh rate updates. The fourth new line of code (line 15) simply initializes our elapsed time running tally variable.

The next step is to define the method that will be called when the display link has an update. Add this code to the bottom of the viewController.swift class, i.e. inside the final class curly brace:



Now for the logic—we are almost there! In the newly created function add the following lines of code:



The first new line of code (line 3) updates our running tally. The second (line 6) formats our running tally into a string that only shows the last two significant digits. The third (line 9) updates our numeric display label.

Let’s move over to the startStopButtonPressed(…) method. This method is called anytime the user presses the button situated to the right in our stop watch scene. When this button is pressed we want to toggle the display link’s “paused” Boolean value. Add the following line of code to this method.



At this point you can run your project and press the start button to see your stop watch in action! Woohoo! Again, if you get any errors and the project does not build correctly, read the error message(s) carefully and see if you can troubleshoot the problem.

Let’s shift our focus to the Reset button. What do you think this button should logically do? It should pause the display link to prevent it from  sending us any further updates, then set the numeric display label to zero, and update our Start/Stop button state. In the resetButtonPressed(…) method add the following lines of code:



Let’s now complete our code project by adding the last few lines of code for our Start/Stop button. In startStopButtonPressed(…) add the code in bold:



Our label text string will not be modified if our code does not fall through our first conditional if statement. If, however, the display link is paused, then we check the running display link tally. If this tally is greater than zero, then we display the resume button since pressing this button again will not reset our running tally. If it’s equal to zero then we display the start text. The button text is set in the last line of code.

Your final ViewController file should look like this.

Finally, let’s add a title label. Go back to the main storyboard. From the object list at the bottom of the File Inspector in the right pane of Xcode, drag a Label to the center/top of your main view. Size it as you like, and provide it with a text title such as “Stopwatch”.  The final product should look something like the three screencaps below, showing the default, running and paused states:

Default State



Running

Paused

And that concludes our simple Stopwatch app tutorial! We leave you off with a question for further reflection.  Notice that our chronometer output is not formatted for standard time. Our implementation increments our minor units, values to the right of the decimal point, from .00 to .99 before increasing the the major unit by one. Although this is a correct unit of measurement, it is not in the ubiquitous standard time format. In the standard format the minor unit, a.k.a the second, is incremented from .00 to .59 before the next major unit, i.e. a minute, is increased by one. Since there are many ways to implement this, some being more efficient than others, we leave this consideration to the reader as an exercise. Post your own solution below. And, as always, feedback, suggestions, and angry tirades are welcome in the comments.

This project can be found on GitHub.

The Stopwatch app and tutorial was originally authored by Stefan Agapie, a Senior iOS Software Engineer, and then adapted for the present piece.