Your First Swift App

In this article by Giordano Scalzo, the author of the book Swift 2 by Example, learning a language is just half of the difficulty in building an app; the other half is the framework. This means that learning a language is not enough. In this article, we'll build a simple Guess a Number app just to become familiar with Xcode and a part of the CocoaTouch framework.

(For more resources related to this topic, see here.)

The app is…

Our first complete Swift program is a Guess a Number app, a classic educational game for children where the player must guess a number that's generated randomly.

For each guess, the game tells the player whether the guess is greater or lower than the generated number, which is also called the secret number.

It is worth remembering that the goal is not to build an Apple's App Store-ready app with a perfect software architecture but to show you how to use Xcode to build software for iOS. So forgive me if the code is not exactly clean and the game is simple.

Before diving into the code, we must define the interface of the app and the expected workflow. This game presents only one screen, which is shown in the following screenshot:

Swift 2 by Example

At the top of the screen, a label reports the name of the app: Guess a Number.

In the next row, another static label field with the word between connects the title with a dynamic label field that reports the current range. The text inside the label must change every time a new number is inserted. A text field at the center of the screen is where the player will insert their guess.

A big button with OK written on it is the command that confirms that the player has inserted the chosen number.

The last two labels give feedback to the player, as follows:

  • Your last guess was too low is displayed if the number that was inserted is lower than the secret number
  • Your last guess was too high is displayed if the number that was inserted is greater than the secret number

The last label reports the current number of guesses. The workflow is straightforward:

  1. The app selects a random number.
  2. The player inserts their guess.
  3. If the number is equal to the secret number, a popup tells the player that they have won and shows them the number of guesses.
  4. If the number is lower than the secret number but greater than the lower bound, it becomes the new lower bound. Otherwise, it is silently discarded.
  5. If the number is greater and lower than the upper bound, it becomes the new upper bound. Otherwise, it's again silently discarded.

Building a skeleton app

Let's start building the app. There are two different ways to create a new project in Xcode: using a wizard or selecting a new project from the menu. When Xcode starts, it presents a wizard that shows the recently used projects and a shortcut to create a new project, as shown in the following screenshot:

Swift 2 by Example

If you already have Xcode open, you can select a new project by navigating to File | New | Project…, as shown in the following screenshot:

Swift 2 by Example

Whichever way you choose, Xcode will ask for the type of app that needs to be created.

The app is really simple. Therefore, we choose Single View Application, as shown in the following screenshot:

Swift 2 by Example

Before we start writing code, we need to complete the configuration by adding the organization identifier using the reverse domain name notation and Product Name. Together, they produce a Bundle Identifier, which is the unique identifier of the app.

Pay attention to the selected language, which must obviously be Swift. Here is a screenshot that shows you how to fill the form:

Swift 2 by Example

Once you're done with this data, you are ready to run the app by navigating to Product | Run, as shown in the following screenshot:

Swift 2 by Example

After the simulator finishes loading the app, you can see our magnificent creation: a shiny, brilliant, white page!

We can stop the app by navigating to Product | Stop, as shown in the following screenshot:

Swift 2 by Example

Now, we are ready to implement the app.

Adding the graphic components

When we are developing an iOS app, it is considered good practice to implement the app outside-in, starting from the graphics. By taking a look at the files generated by the Xcode template, we can identify the two files that we'll use to build the Guess a Number app:

  • Main.storyboard: This contains the graphics components
  • ViewController.swift: This handles all the business logic of the app

Here is a screenshot that presents the structure of the files in an Xcode project:

Swift 2 by Example

Let's start by selecting the storyboard file to add the labels.

The first thing that you will notice is that the canvas is not the same size or ratio as that of an iPhone and an iPad. To handle different sizes and different devices, Apple (since iOS 5) added a constraints system called Auto Layout as a system to connect the graphics components in a relative way regardless of the actual size of the running device.

As Auto Layout is beyond the scope of this article, we'll implement the created app only for iPhone 6.

After deciding upon the target device, we need to resize the canvas according to the real size of the device. From the tree structure to the right, we select View Controller, as shown in the following screenshot:

Swift 2 by Example

After doing this, we move to the right, where you will see the properties of the View Controller. There, we select the tab containing Simulated Metrics; in this, we can insert the requested size. The following screenshot will help you locate the correct tab:

Swift 2 by Example

Now that the size is what's expected, we can proceed to add labels, text fields, and the buttons from the list at the bottom-right corner of the screen.

To add a component, we must choose it from the list of components. Then, we must drag it onto the screen, where we can place it at the expected coordinates.

The following screenshot shows the list of UI components called an object library:

Swift 2 by Example

When you add a text field, pay attention to how we select Number Pad as the value for Keyboard Type, as illustrated in the following screenshot:

Swift 2 by Example

After selecting the values for all the components, the app should appear as shown in the mockup that we had drawn earlier, which can be confirmed in the following screenshot:

Swift 2 by Example

Connecting the dots

If we run the app, the screen is the same as the one in the storyboard, but if we try to insert a number into the text field and then press the OK button, nothing happens.

This is so because the storyboard is still detached from the View Controller, which handles all the logic.

To connect the labels to the View Controller, we need to create instances of a label prepended with the @IBOutlet keyword. Using this signature, the graphic editor inside Xcode named Interface Builder can recognize the instances available for a connection to the components:

class ViewController: UIViewController {
    @IBOutlet weak var rangeLbl: UILabel!
    @IBOutlet weak var numberTxtField: UITextField!
    @IBOutlet weak var messageLbl: UILabel!
    @IBOutlet weak var numGuessesLbl: UILabel!

    @IBAction func onOkPressed(sender: AnyObject) {
    }
}

We have also added a method with the @IBAction prefix, which will be called when the button is pressed. Now, let's move on to Interface Builder to connect the labels and outlets. First of all, we need to select View Controller from the tree of components, as shown in the following screenshot:

Swift 2 by Example

In the tabs to the right, select the outlet views; the last one with an arrow is a symbol. The following screenshot will help you find the correct symbol:

Swift 2 by Example

This shows all the possible outlets to which a component can be connected.

Upon moving the cursor onto the circle beside the rangeLbl label, we see that it changes to a cross. Now, we must click and drag a line to the label in the storyboard, as shown in the following screenshot:

Swift 2 by Example

After doing the same for all the labels, the following screenshot shows the final configurations for the outlets:

Swift 2 by Example

For the action of the button, the process is similar. Select the circle close to the onOkPressed action and drag a line to the OK button, as shown in the following screenshot:

Swift 2 by Example

When the button is released, a popup appears with a list of the possible events that you can connect the action to.

In our case, we connect the action to the Touch Up Inside event, which is triggered when we release the button without moving from its area. The following screenshot presents the list of the events raised by the UIButton component:

Swift 2 by Example

Now, consider a situation where we add a log command like the following one:

@IBAction func onOkPressed(sender: AnyObject) {
        println(numberTxtField.text)
    }

Then, we can see the value of the text field that we insert and which is printed on the debug console. Now that all the components are connected to their respective outlets, we can add the simple code that's required to create the app.

Adding the code

First of all, we need to add a few instance variables to handle the state, as follows:

    private var lowerBound = 0
    private var upperBound = 100
    private var numGuesses = 0
    private var secretNumber = 0

Just for the sake of clarity and the separation of responsibilities, we create two extensions to the View Controller. An extension in Swift is similar to a category in Objective-C programming language, a distinct data structure that adds a method to the class that it extends.

Since we don't need the source of the class that the extension extends, we can use this mechanism to add features to third-party classes or even to the CocoaTouch classes.

Given this original purpose, extensions can also be used to organize the code inside a source file. This may seem a bit unorthodox, but if it doesn't hurt and is useful. So why not use it?

The first extension contains the following logic of the game:

private extension ViewController{
   enum Comparison{
        case Smaller
        case Greater
        case Equals
    }

   func selectedNumber(number: Int){
}
    
   func compareNumber(number: Int, otherNumber: Int) -> Comparison {
}
}

Note that the private keyword is added to the extension, making the methods inside private. This means that other classes that hold a reference to an instance of ViewController can't call these private methods.

Also, this piece of code shows that it is possible to create enumerations inside a private extension.

The second extension, which looks like this, is used to render all the labels:

private extension ViewController{
    func extractSecretNumber() {
    }
    
    func renderRange() {
    }
    
    func renderNumGuesses() {
}    
    func resetData() {
}    
    func resetMsg() {
}    
    func reset(){
        resetData()
        renderRange()
        renderNumGuesses()
        extractSecretNumber()
        resetMsg()
    }
}

Let's start from the beginning, which is the viewDidLoad method in the case of the View Controller:

override func viewDidLoad() {
        super.viewDidLoad()
  numberTxtField.becomeFirstResponder()
        reset()
    }

When the becomeFirstResponder method is called, the component called numberTxtField in our case gets the focus and the keyboard appears.

After this, the reset() method is called, as follows:

func reset(){
        resetData()
        renderRange()
        renderNumGuesses()
        extractSecretNumber()
        resetMsg()
    }

This basically calls the reset method of each component, as follows:

func resetData() {
        lowerBound = 0
        upperBound = 100
        numGuesses = 0
    }
    
    func resetMsg() {
        messageLbl.text = ""
    }

Then, the method is called and is used to render the two dynamic labels, as follows:

func renderRange() {
        rangeLbl.text = "\(lowerBound) and \(upperBound)"
    }
    
    func renderNumGuesses() {
        numGuessesLbl.text = "Number of Guesses: \(numGuesses)"
    }

The reset method also extracts the secret number using the arc4random_uniform function and performs some typecast magic to align numbers to the expected numeric type, as follows:

func extractSecretNumber() {
        let diff = upperBound - lowerBound
        let randomNumber = Int(arc4random_uniform(UInt32(diff)))
        secretNumber = randomNumber + Int(lowerBound)
      }

Now, all the action is in the onOkPressed action (pun intended):

@IBAction func onOkPressed(sender: AnyObject) { 
        guard let number = Int(numberTxtField.text!) else {
            let alert = UIAlertController(title: nil, message: "Enter a number", preferredStyle: UIAlertControllerStyle.Alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
            self.presentViewController(alert, animated: true, completion: nil)
            return
        }
        selectedNumber(number)
    }

Here, we retrieve the inserted number. Then, if it is valid (that is, it's not empty, not a word, and so on), we call the selectedNumber method. Otherwise, we present a popup that asks for a number. This code uses the guard Swift 2.0 keyword that allows you to create a really clear code flow.

Note that the text property of a UITextField function is optional, but because we are certain that it is present, we can safely unwrap it.

Also, the handy Int(String) constructor converts a string into a number only if the string is a valid number.

All the juice is in selectedNumber, where there is a switch case:

func selectedNumber(number: Int){
        switch compareNumber(number, otherNumber: secretNumber){
  //

The compareNumber basically transforms a compare check into an Enumeration:

func compareNumber(number: Int, otherNumber: Int) -> Comparison{
        if number < otherNumber {
            return .Smaller
        } else if number > otherNumber {
            return .Greater
        }
        
        return .Equals
    }

Let's go back to the switch statement of selectedNumber; it first checks whether the number inserted is the same as the secret number:

case .Equals:
let alert = UIAlertController(title: nil, 
              message: "You won in \(numGuesses) guesses!",
              preferredStyle: UIAlertControllerStyle.Alert)
            alert.addAction(UIAlertAction(title: "OK", 
              style: UIAlertActionStyle.Default, 
              handler: { cmd in
                self.reset()
                self.numberTxtField.text = ""
              }))
            self.presentViewController(alert, 
              animated: true, completion: nil)

If this is the case, a popup with the number of guesses is presented, and when it is dismissed, all the data is cleaned and the game starts again.

If the number is smaller, we calculate the lower bound again and then render the feedback labels, as follows:

case .Smaller:
            lowerBound = max(lowerBound, number)
            messageLbl.text = "Your last guess was too low"
            numberTxtField.text = ""
            numGuesses++
            renderRange()
            renderNumGuesses()

If the number is greater, the code is similar, but instead of the lower bound, we calculate the upper bound, as follows:

case .Greater:
            upperBound = min(upperBound, number)
            messageLbl.text = "Your last guess was too high"
            numberTxtField.text = ""
            numGuesses++
            renderRange()
            renderNumGuesses()
        }

Et voilà! With this simple code, we have implemented our app.

You can download the code of the app from https://github.com/gscalzo/Swift2ByExample/tree/1_GuessTheNumber.

Summary

This article showed us how, by utilizing the power of Xcode and Swift, we can create a fully working app.

Depending on your level of iOS knowledge, you may have found this app either too hard or too simple to understand. If the former is the case, don't loose your enthusiasm. Read the code again and try to execute the app by adding a few strategically placed println() instructions in the code to see the content of the various variables. If the latter is the case, I hope that you have found at least some tricks that you can start to use right now.

Of course, simply after reading this article, nobody can be considered an expert in Swift and Xcode. However, the information here is enough to let you understand all the code.

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Swift 2 By Example

Explore Title