Add 1: Creating A Simple iOS Game With Swift in Xcode (Part 3)

Written by: Reinder de Vries, March 15 2015, in Add 1, Programming

Updated for Xcode 8 and Swift 3

Project Code, Assets and This Series

This code guide is part of a series with 3 parts in total. Check out all 3 parts here:

  1. Add 1: Creating A Simple iOS Game With Swift in Xcode (Part 1)
  2. Add 1: Creating A Simple iOS Game With Swift in Xcode (Part 2)
  3. Add 1: Creating A Simple iOS Game With Swift in Xcode (Part 3)

Download the Xcode project and assets with these links:

Supercharge your next app project

Grab the App Toolbox 2017 to learn how to save time building your app
and how to get thousands of app installs in the App Store.

Grab The App Toolbox

MBProgressHUD and Cocoapods

Alright, we’re going to use a library for the next part of this tutorial. In order to show a notification to the user, to inform them whether their answer was right or wrong, we’ll use a progress HUD.

It’s one of those little black squares that pop up when you do something on your iPhone, to inform you that stuff is happening.

A very fine framework as been built for such HUDs and it’s called MBProgressHUD. We can download the source code for the framework on GitHub and inspect it ourselves. While GitHub is great for finding and making use of someone elses code, there’s a better alternative for getting that code inside our project. You see, in order to work with third-party code, we need to import it in our project as a library.

And we’re gonna do that with Cocoapods. Cocoapods is a dependency manager, a quick way to import and maintain third-party code that we use in our projects. In order to work with it, we just declare a file, write down the names of the libraries we want to use, and Cocoapods takes care of the rest.

We install Cocoapods on a Mac by going to the Terminal app, and writing this on the command-line (without the $ sign):

$ sudo gem install cocoapods

After a while (it’s downloading), we should see this:

Successfully installed cocoapods-0.35.0
Parsing documentation for cocoapods-0.35.0
1 gem installed

Now, get back to Xcode and create a new empty file. You do that by right-clicking on the project in the Project navigator on the left, then choosing New file... and picking the Empty file type from the iOS -> Other category. Create the file in the root (topmost) directory of the project. Name the file Podfile, without extension.

Paste the following text in the new file:

source ''
platform :ios, '9.0'

target "Add 1" do
    pod 'MBProgressHUD', '1.0.0'

Then, go back to Terminal and cd into the directory of your app. If you don’t know how to do that, just do this:

  1. Write cd (with an ending space) on the command-line.
  2. Open Finder, and go to the root directory of your project.
  3. Drag the project folder onto the Terminal window. It should write out the directory path on the command-line.
  4. Hit Enter.

Now, when in the right directory, type this in Terminal:

$ pod install

In case you get a No such file or directory error, run this command before running pod install:

$ pod setup

Then, an important step:

  1. Close Xcode.
  2. Go in Finder to your projects root directory.
  3. Click on the Add1.xcworkspace (or any other .xcworkspace project) file.

Cocoapods adds a new project to our project, so we can’t simply work with our old project anymore. We need to work within the Workspace, that contains both projects. Cocoapods has added our dependent library (MBProgressHUD).

Watch the video to see how to install CocoaPods and work with Terminal.

Adding a Bridging Header to use an Objective-C library

The MBProgressHUD library is written in Objective-C, and that’s not immediately compatible with Swift code. Fortunately, we can create a so-called bridging header to use the library from within our Swift code.

Creating a Bridging Header goes like this:

  1. Creata a new file in the Add1 project, by right-clicking on the project and choosing New file....
  2. Then, pick Header file from the iOS -> Source category.
  3. Name the file Add1-Bridging-Header.h and save it in the project root directory.

Then, do this:

  1. Click on the project in the Project navigator.
  2. Up top, click on the Build Settings tab. (Don’t see it? Make sure Add1 is selected, under Targets on the left.)
  3. In the search box (top right), type in bridging. The list below should filter, and show a field called Objective-C Bridging Header.
  4. Double-click on the empty field contents (the column right of the bold-typed Objective-C Bridging Header).
  5. Input in the field: Add1-Bridging-Header.h.

Finally, edit the Add1-Bridging-Header.h file and write the following line in it:

#import <MBProgressHUD/MBProgressHUD.h>

Check whether you’ve implemented the Bridging Header right, by building the project with Command-B. If all goes well, you don’t see any errors.

What did we just do?

Swift and Objective-C can be integrated with one another by creating a connection, a Bridging Header. Both languages work with header files, a certain type of file that describes the methods of a class to the compiler. But, both Swift and Objective-C have different syntax for describing classes and functions. A Bridging Header mediates between the two, it translates from one language to the other by creating a “bridge”.

Importing image assets

Alright, lets integrate MBProgressHUD with our project. We’ll use it to show the user a thumbs up, or thumbs down, when they’ve answered a question, and hide it after 3 seconds.

We’ll use 2 different files:

  1. Image file [email protected]
  2. Image file [email protected]

Import like this:

  1. In Xcode, click on the Images.xcassets file in Project navigator. The asset library should open now.
  2. From Finder, drag the 2 files to the left part of the asset library.

Two items now should be created, thumbs-down and thumbs-up.

Watch the video to see how to work with image assets.

Using MBProgressHUD

We’ll now incorporate MBProgressHUD in our code.

First, add the following line to the top of MainViewController.swift right below import UIKit:

import MBProgressHUD

Then, add an MBProgessHUD instance variable to the MainViewController class, by adding this file to the top of the class, just under the score variable declaration.

var hud:MBProgressHUD?

Note that it is an optional!

Then, add in viewDidLoad the following code, just under super.viewDidLoad().

hud = MBProgressHUD(view:self.view)

if(hud != nil)

What does this code do? It’s this:

  1. Initialize an instance of MBProgressHUD and assign it to instance variable hud. The constructor method MBProgressHUD() has one named parameter: view. We put self.view in there. It tells the new instance: create yourself, and you’ll be added to self.view later! The HUD now knows where it is. The variable self.view (or: property view on variable self) is a reference to the current view.
  2. If hud is not empty, add it as a subview to the current view. Notice the exclamation mark? We can force unwrap the optional hud, because we verified that it is not nil.

Then, add this function to the MainViewController class, right under the closing squiggly bracket } of viewDidLoad.

func showHUDWithAnswer(isRight:Bool)
    var imageView:UIImageView?

    if isRight
        imageView = UIImageView(image: UIImage(named:"thumbs-up"))
        imageView = UIImageView(image: UIImage(named:"thumbs-down"))

    if(imageView != nil)
        hud?.mode = MBProgressHUDMode.customView
        hud?.customView = imageView

        hud?.show(animated: true)

        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            self.hud?.hide(animated: true)
            self.inputField?.text = ""

Whoah! That’s an entirely new method!

What does it do?

First, these are the characteristics of the method. Can you spot:

  1. That it’s name is showHUDWithAnswer?
  2. That it has one unnamed parameter: isRight?
  3. That the type of that parameter is boolean: Bool, so it only can be true or false?

So, we can deduct that this method must show the HUD, considering the correctness of the answer. Right?

Then, from top to bottom, this is what happens inside the method:

  1. First, we create an empty variable called imageView of type UIImageView?. It doesn’t have a value, because we don’t initialize it. Initialization happens according to method parameter isRight: when the answer is right, we load up an image view containing the “thumbs-up” image, if it’s wrong, the image will show “thumbs-down”.
  2. Then, if hudImageView is not nil (remember, it could be nil because the images didn’t load!) the HUD is configured and put on screen.
    • First, we assign the property mode the value of MBProgressHUDMode.CustomView. That’s just a configuration code, like saying it’s type 1 or 2 or 3, but then with code.
    • Second, we assign our image view to the customView property. It will override MBProgressHUDs standard image with our image view, of either the “right” image, or the “wrong” image.
    • Third, we show the HUD by calling method show(). The parameter true means that the showing will be animated.
    • Finally, we instruct the HUD to hide after 3 seconds with the DispatchQueue.main.asyncAfter(... code.

That last method is kinda special! In short, it makes use of Grand Central Dispatch. It takes 3 parameters: the execution time, the dispatch queue, and a closure with the actual code. It executes the code inside the closure with a delay.

Finally, we need to put the new method to use.

In the textFieldDidChange: method, add the following two codes somewhere:

showHUDWithAnswer(isRight: true)


showHUDWithAnswer(isRight: false)

Where? Well, the first one is a response to a right answer, and the second to a wrong answer.

Let’s add them inside the if-statement, right under score += 1 and score -= 1. Can you figure out which one you need to add where?

Run the app!

See if what you just made is working! You should be able to enter a number, and then see the HUD briefly appear with either a thumbs up or down.

Well done!

Adding A Timer

A game is not a game if there’s no time pressure. Let’s add a timer to our game! These are its “rules”:

  1. The timer counts down from 1 minute to 0 seconds.
  2. When it reaches zero, the game stops.
  3. The timer has to start once the first answer is given.

Of course, the goal of the game is to get as many points as possible before the timer runs out.

Coding The Timer

First, let’s create 2 new instance variables at the top of MainViewController.swift. Open up Xcode if you have not done so already, and locate the file. Add these two lines at the top of the class, just below the declaration of hud.

var timer:Timer?
var seconds:Int = 60

First, you create an object that is called timer and is of type Timer. It’s a complex timer that allows you to schedule tasks, execution of code, within an interval of time. Perfect for counting down from 1 minute to zero. Note that the variable is an optional.

Second, you create a simple variable called seconds of type Int and directly set it to 60, or 1 minute in seconds.

Now, let’s set up the timer itself. We want it to start counting once the first answer is given. The user can start the game at their own pace, but once they’ve started, the clock starts ticking.

Locate the textFieldDidChange: method of our class, and input the following code at the very end, just below updateScoreLabel(), but before the squiggly closing bracket.

if(timer == nil)
    timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector:#selector(onUpdateTimer), userInfo:nil, repeats:true)

Alright! Note the if-statement — what does it do? It checks whether timer is nil, whether it’s empty and not initialized. The code inside the if-block, sets the timer. If we wouldn’t use the if-statement, the timer would reset itself each time a game answer is given! We only want to set it once, and then let it run out. Later on, we set the timer to nil when it reaches zero. So, a perfect loop is made: create the timer if it is nil, let it run until zero, set it to nil, and restart.

The inside of the if-block does this:

  1. Assign to timer with the =-sign.
  2. Call class method scheduledTimer(timeInterval:target:selector:userInfo:repeats:), which returns a timer instance that is assigned to timer.
  3. First parameter: 1 second, the interval of the timer, so it calls once every second.
  4. Second and third parameter: the target and the selector. It indicates a method on the target that should be run when the timer fires (once every second). So, when the timer fires, execute method onUpdateTimer of self, and self is our current class MainViewController. We’ll create that method later.
  5. Fourth and fifth: userInfo allows us to give the timer some extra data, but we won’t use it, so it’s set to nil. Then, repeats is set to true: we want to repeat the timer until we reset it.

Coding The Firing Of The Timer

Now, add this function to the class:

func onUpdateTimer() -> Void
    if(seconds > 0 && seconds <= 60)
        seconds -= 1

    else if(seconds == 0)
        if(timer != nil)
            timer = nil

Can you figure out what the code is for the following features?

  1. When the second variable is between 0 and 60 (60 included), decrease it with 1 step and execute updateTimeLabel().
  2. When second is zero (and point 1 is false, i.e. not between 0 and 60) and timer not is nil, invalidate the timer and erase it by setting it to nil.

Got it?

We either downstep the timer, or reset it.

Creating Another Outlet And Writing The Seconds Left

Now, create a new outlet. Do you remember how?

First, add a property to MainViewController like this:

@IBOutlet weak var timeLabel:UILabel?

We designate it to be an outlet by using the @IBOutlet statement. We now can connect to it with Interface Builder. Switch to the XIB file and Control-draw a line from File’s Owner to the time label top-right. Remember: creating an outlet means you connect an interface element from IB to your code, by first writing the outlet declaration in a class, and then drawing a line in Interface Builder.

You might want to change the timeLabel text to 01:00 in Interface Builder.

Alright, next function! Add the method below to class MainViewController, just like before.

func updateTimeLabel()
    if(timeLabel != nil)
        let min:Int = (seconds / 60) % 60
        let sec:Int = seconds % 60

        let min_p:String = String(format: "%02d", min)
        let sec_p:String = String(format: "%02d", sec)

        timeLabel!.text = "\(min_p):\(sec_p)"

What happens here? Well, we want to update the time label with a 00:00 minute-second format. First, we only attempt to set the text on timeLabel when the outlet exists and is not nil.

Then, we create 4 constants. let declares constants, var declares variables, and a constant is just a variable that never changes during the course of our program. Constants are bound to a scope, just like any other variable, so they remain constant during the course of the method updateTimeLabel.

  1. min, type Int, cleverly extracts the number of minutes from an amount of seconds. See, 60 seconds is 1 minute, or 01:00 and not 00:60. How do we write that? First, we divide seconds by 60, and then take the remainder of the result (with the modulo sign, %).
  2. sec, type Int, simply takes the remainder of seconds divided by 60 — the number of seconds that remain, once all the minutes are taken “out”.
  3. min_p and sec_p, type String, are a formatting of min and sec into zero-padded strings. The format indicator %02d means: always write me with two digits, and when there’s initially only one digit, prefix me with a zero.

Finally, we assign a concatenated string literal "\(min_p):\(sec_p)" to property text of force-unwrapped optional timeLabel.

Score Not Lower Than Zero

In order to make the gaming experience more fun and less strict, lets make sure you can’t have a score below zero. How?

In the code, there’s one line where we add 1 or subtract 1 from the score. We want to change the subtraction, and only allow it when the score is above zero. Can you figure out where?

When the score is 1 (1 > 0 == true) then subtract one from it, making the score 0. When the score is 0 (0 > 0 == false), don’t subtract. Do you understand that the if-statement conditional must be score > 0 (bigger-than) and not score >= (bigger-than-or-equal)?

Locate the right line, and make sure it resembles this:

if(score > 0) {
    score -= 1

Just for fun. Can you rewrite the scoring mechanism so that you can’t have a score greater than 100?

Uppacing The Tempo

Remember the hud we used? It’s a modal view that shows you whether your input is wrong or right. It’s set to remain on-screen for 3 seconds, which greatly influences the maximum score by eating up game time. Let’s adjust it.

Find the line that uses Grand Central Dispatch in the code, and change the 3 on that line into 1. It should then look like this:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {


Aw yiss! We got the timer added. Can you build and run the game, and figure out whether you’ve implemented the above code right?

Let’s see.

Resetting After The Timer Reaches Zero

Alright, we’re missing just one thing: a reset! When the timer reaches zero, we gotta tell the user their score and set the game up for another round.

Let’s do just that. Take a look at the code below.

let alertController = UIAlertController(title: "Time Up!", message: "Your time is up! You got a score of: \(score) points. Very good!", preferredStyle: .alert)

let restartAction = UIAlertAction(title: "Restart", style: .default, handler: nil)

self.present(alertController, animated: true, completion: nil)

score = 0
seconds = 60


What happens here?

  1. First, we create another constant with name alertController and type UIAlertController. It’s a complex type that puts a modal alert box on screen. Check out the parameters: the title, a message, then a delegate (we won’t use that) and a button that dismisses the modal alert box.
  2. Then, we put it on screen with the method presentViewController:animated:completion:.
  3. Then, we set score and seconds to zero, a reset. Setting those to zero doesn’t update the screen though, only the internal variables!
  4. Finally, we call our methods to update the time and score label, and create a new first number for the next round.

Where do you add this code?

In onUpdateTimer maybe? Yes! Why? That update method holds the perfect game context, because a game ends when the timer reaches zero: else if(seconds == 0). Change its contents (not the original if-statement itself!) so it resembles:

if(timer != nil)
    timer = nil

    let alertController = UIAlertController(title: "Time Up!", message: "Your time is up! You got a score of: \(score) points. Very good!", preferredStyle: .alert)
    let restartAction = UIAlertAction(title: "Restart", style: .default, handler: nil)

    self.presentViewController(alertController, animated: true, completion: nil)

    score = 0
    seconds = 60


Build and play your app again, to see if all went well. When the timer reaches zero, does it show the alert popup and reset the game? Awesome!

Supercharge your next app project

Grab the App Toolbox 2017 to learn how to save time building your app
and how to get thousands of app installs in the App Store.

Grab The App Toolbox

That’s It!

That’s it for now folks! You did a great job creating this Add 1 game, very well done! Bear with LearnAppMaking to stay updated on future tutorials, and read up on app publishing tactics on the blog in the meantime.

What did we learn?

  1. Using timers with Timer, invoking selectors on a target.
  2. Updating code by inserting new lines, without knowing what the code should look like (did you notice the different with last week?).
  3. Working with UIAlertView.
  4. More complex conditionals (if-statements), introducing if-then-elseif-else and bigger-than and bigger-or-equal-than.
  5. String formatting, zero-padding and the modulo operator.
  6. How to be an awesome app maker! (Hint: you already are!)


It wouldn’t be a course without a little challenge? See if you can change the game and it’s mechanics to solve the challenges below.

  1. Give users 2 minutes, or 120 seconds, of game time. (You do need to change an if-statement, too.)
  2. Adjust the scoring mechanism: the time decreases twice as fast when your score is above 10.
  3. Allow zeroes to be included in the random number. To do so, you must zero-pad the digit variable, to allow it to be 0123 for instance.
  4. Allow nines to be included in the random number. The “check if this answer is right” then needs a complete overhaul, because the difference won’t be 1111 anymore. Note: 0397 becomes 1408.

Good luck!

Join 11.000+ app developers and marketers
  • Get a weekly curated list of app development tools, articles and resources in your inbox
  • 10x your app installs with relevant App Store Optimization and app marketing strategies
  • BONUS: Grab a free copy of the App Toolbox 2017 to supercharge your next app project
Yes, Sign Me Up!

Popular Posts

Written By: Reinder de Vries

Reinder de Vries is an indie app maker who teaches aspiring app developers and marketers how to build their own apps at He has developed 50+ apps and his code is used by millions of users all over the globe. When he’s not coding, he enjoys strong espresso and traveling.

Supercharge your next app project

Grab the App Toolbox 2017 to learn how to save time building your app
and how to get thousands of app installs in the App Store

Grab The App Toolbox

Comments & Thoughts

Leave a Reply

Markdown is supported (Learn more). Your email address will not be published. Required fields are marked with *

  • Novice App Maker (December 22, 2016)

    Accidentley deleted all the graphics from assets.xcassets. When I go to the link to just get new ones the graphics were gone. What to do?

  • Novice App Maker (December 22, 2016)

    nevermind I fixed it

  • Reinder de Vries (December 21, 2016)

    Put a space between the "cd" and the file path, like this:

    cd /Applications/Xcode projects/Add1
  • Novice App Maker (December 21, 2016)

    When I drag my project into terminal and hit enter it says ' No such file or directory'
    I type in 'cd/Applications/Xcode projects/Add1'.

  • Reinder de Vries (June 19, 2016)

    Yeah sure, there's a link for the Xcode project file at the top of this page!

  • Cameron (June 19, 2016)

    I can't find a problem in my code! Could you send me a copy of all the code to try that

  • Reinder de Vries (June 18, 2016)

    What do you mean? Check if you've added the method that will reset the game after the user inputs an answer. It's in the guide.

  • Cameron (June 18, 2016)

    hello, my code does not automatically go to the next one if it s correct! What should I do about it?

  • James Ikeler (May 21, 2016)

    Hey can I use your assets for your own game on the ios app store(I'm just taking the assets not the code I will leave a link to the image or the course in your want)

  • Reinder de Vries (September 1, 2015)

    Yes, invalidating the timer resets it. You need to create a new timer with:


    When you want to invalidate the timer, do this:

    timer = nil;

    That'll force you to reset the timer, because it's "nil", so you can't forget it :-)

    Good luck!

On The Blog