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!
Author: Mohit Deshpande