Swift for Beginners: Writing a Guessing Game iOS App

3 Mohit Deshpande Jul 9, 2014

In this tutorial, we're going to get a glimpse of Swift, Apple's new programming language, in the context of an iOS application: we'll be building a simple guessing game. If you need to get up to speed on the new language, check out my Swift for Beginners Course! Now get 80% off of the course using the coupon code: binpress-swift!

Requirements

An Apple computer running XCode 6.

Disclaimer: Due to the Apple NDA, I am not legally permitted to post screenshots of the XCode 6 beta or iOS 8 beta.

What is Swift?

Swift is Apple's new programming language announced and showcased at the 2014 Worldwide Developer Conference (WWDC) in early June. It was described as "Objective-C without the C," and touts many improvements over Objective-C such as inferred data types, optional semicolons, tuples, and optionals. This new programming language can be used to write iOS and OS X apps, and can run concurrently with Objective-C, allowing developers to fully utilize both Objective-C and Swift. In fact, entire applications can be written solely in Swift.

Guessing Game

Over this tutorial, we're going to build a guessing game iOS app with Swift. The app will randomly generate a number from 1 to 100, and you have to guess which number is generated. It will tell you if you're too low or too high, but the catch is that you only have 8 tries to guess the correct number!

Create the XCode Project

Due to the the Apple NDA, I can't legally post a screenshot of XCode, but I can guide you through the process. Open up XCode and create a new Single View Application via File->New->Project. Make sure to choose Swift as the language.

User Interface

Again, I can't post a screenshot of the UI in Interface Builder (IB), but I can describe it to you. For the purposes of this tutorial, the guessing game will be done in a console-like fashion. At the top, we'll need a UITextField to get user input. A UIButton will be right underneath that so users can press it to submit their guess. Finally, an immutable UITextView will take up the remainder of the space to act as a console output.

Outlets and Actions

The aforementioned views will be usable in our Swift code through several outlets and actions:

@IBOutlet var inputField : UITextField
@IBOutlet var output : UITextView
@IBAction func guess(sender : UIButton) {
    ...
}

guess is the action that occurs when the UIButton is pressed.

Variables and Constants

Before we get into the actual game loop, we need to declare some important member variables and constants first:

var guesses : UInt = 0
var number : UInt32 = 0
var gameOver = false
let MAX_GUESSES : UInt = 8

Variables are declared with the var keyword, followed by the name and possibly a type annotation, : UInt for unsigned integer. Finally, they can be initialized at the same time they're declared. Type annotations are optional due to Swift's inferred data types: gameOver is inferred to be a Bool. We can declare constants in the same way as variables, except we use let instead of var.

Functions

We're going to need some utility functions in the future, so we'll define them now:

func consoleOut(text : String) {
    output.text = output.text + text
}

func generateNewNumber() -> UInt32 {
    return arc4random_uniform(100) + 1
}

func clearInput() {
    inputField.text = ""
}

Functions are declared via the func keyword. The function name follows. Parameters are put in the parentheses and they must have a type annotation. Return types are placed after the parameters and the return arrow: ->. The consoleOut function simply appends text to output using the string concatenation operator, +. No more dealing with messy NSString functions! The second function generates a random number between 1 and 100, and the final function clears inputField.

Starting the Game

We'll want to begin the game by generating a random number as soon as the application is opened. An ideal place to do this is in the viewDidLoad function:

override func viewDidLoad() {
    super.viewDidLoad()

    number = generateNewNumber()
    consoleOut("I'm thinking of a number...\n")
}

Guessing

We should begin the guess function by getting the user's input from inputField:

var possibleGuess : Int? = inputField.text.toInt()

We can convert the text in inputField to an integer using toInt(), but you'll notice there's a strange type: Int?.

Optionals

After any type, we can put a question mark to declare that type as being optional. An optional type is either when:

  • There is a value and it's "x"
  • Or there isn't a value at all

possibleGuess either exists and has an assigned value, or the toInt() function failed to return a value at all and is therefore nil. We need a way to check if we have a valid integer, and, if not, notify the user that they entered an invalid number.

Optional Binding

Luckily, there's a Swift construct we can use to do just this:

if let guess = possibleGuess {
    // possibleGuess exists!
} else {
    // possibleGuess doesn't exist!
}

Using this if-let construct, we check to see if possibleGuess has a value. If it does, then implicitly unwrap that value into a constant called guess. Within the if portion, we can use guess as the value for possibleGuess. Within the else portion, we'll have to notify the user that they didn't enter in a correct value:

if let guess = possibleGuess {
    // possibleGuess exists!
} else {
    consoleOut("Please input a valid number!\n")
    clearInput()
}

Now let's focus on when the user did input a valid number. If the guessed number was higher than the actual number, then let the user know. Follow the same procedure if the guessed number was lower than the actual number. If neither of those statements are true, then the user guessed the correct number, and they win! We'll also print out their guess for convenience and increment guesses:

if UInt32(guess) > number {
    consoleOut("\(guess): You guessed too high!\n")
    ++guesses
} else if UInt32(guess) < number {
    consoleOut("\(guess): You guessed too low!\n")
    ++guesses
} else {
    consoleOut("\n\(guess): You win!\n")
    consoleOut("Go again? (Y)")
    guesses = 0
    gameOver = true
}
clearInput()

Typecasting

In Swift, we can typecast one type to another type by first specifying what type we want to cast a variable to and what variable we want to cast:

UInt32(guess)

We're casting guess into a UInt32.

String Interpolation

We can insert the values of a variable right into a string. In order to do this, inside the string, put a backslash and surround with parentheses the variable you want to insert:

consoleOut("\(guess): You guessed too high!\n")

This will insert the value of guess into the string.

Lose Scenario

After the user takes a guess and guesses is incremented, we'll have to check to make sure they haven't reached the maximum number of guesses. If they did, they lose. Reset the game data and let the user restart:

if (guesses == MAX_GUESSES) {
    consoleOut("\nYou lose :(\n")
    consoleOut("Go again? (Y)")
    guesses = 0
    gameOver = true
}

Restart?

When the game is over -- either by winning or losing -- instead of asking for a number, we want to ask for a letter. If that letter is "Y", then we'll generate another random number and reset all of the fields and data. Afterwards, we can return from the function since the rest of the function isn't applicable yet. We should check to make sure the game is over before we get numerical input from the user, so we'll put this check at the very beginning of the guess function:

if gameOver {
    var newGame = inputField.text.substringToIndex(1)
    if newGame == "Y" {
        gameOver = false
        output.text = ""
        clearInput()
        number = generateNewNumber()
        consoleOut("\n\nI'm thinking of a number...\n")
        return
    }
}

The substringToIndex will give us a string, starting from the first character, up to but not including the character at the index. We only need the first character, therefore, since strings are zero-indexed, we'll need the substring from the beginning of the string (at index 0) up to but not including the second character (at index 1).

Entire guess function

@IBAction func guess(sender : UIButton) {
    if gameOver {
        var newGame = inputField.text.substringToIndex(1)
        if newGame == "Y" {
            gameOver = false
            output.text = ""
            clearInput()
            number = generateNewNumber()
            consoleOut("\n\nI'm thinking of a number...\n")
            return
        }
    }
    var possibleGuess : Int? = inputField.text.toInt()
    if let guess = possibleGuess {
        if UInt32(guess) > number {
            consoleOut("\(guess): You guessed too high!\n")
            ++guesses
        } else if UInt32(guess) < number {
            consoleOut("\(guess): You guessed too low!\n")
            ++guesses
        } else {
            consoleOut("\n\(guess): You win!\n")
            consoleOut("Go again? (Y)")
            guesses = 0
            gameOver = true
        }
        clearInput()

        if (guesses == MAX_GUESSES) {
            consoleOut("\nYou lose :(\n")
            consoleOut("Go again? (Y)")
            guesses = 0
            gameOver = true
        }

    } else {
        consoleOut("Please input a valid number!\n")
        clearInput()
    }
}

Now it's time to run the application! Click on the Run button on the top-left corner of XCode and view the fruits of our labour!

Conclusion

Over the course of this tutorial, we created a simple Guessing Game iOS app where users guess what number the app randomly generates. Along the way, we learned a few unique Swift language features such as optionals, optional binding, and string interpolation. We also picked up some of Swift's new syntax regarding the declaration variables, constants, functions, typecasting and string concatenation.

If you want to learn more about Swift, check out my Swift for Beginners Course!

3 comments


Or enter your name and Email
  • A Aby 3 years ago
    Error: Line 3 of Entire Guess game displays error in Xcode Beta4+ Follow below http://stackoverflow.com/a/24122445/4448371
  • T Tobitron 3 years ago
    Nice tutorial but too many holes for me to follow as a beginner. Where should these functions and variables be going for example? How are the controls hooked up in the view controller? All glossed over. If you update this with: 1) a video of your screen creating the tutorial 2) the source code on Github so i can just look at it That would be super helpful!
  • JM James McNab 3 years ago
    Great tutorial. I'm going to share this on my website http://madrasa.ca