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

Written by: Reinder de Vries, March 8 2015, in App Development, App Projects

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:

Got a killer app idea?

Grab the App Toolbox 2017 to learn how to save time building your app, and how to 10x your app installs in the App Store. With the toolbox, you’ll immediately know how to move forward to build better, more profitable apps.

Get The App Toolbox

Writing the MainViewController code

Alright, let’s do some more coding. Switch to MainViewController.swift. Do you notice the structure of the file?

  • First, there’s an import statement. It tells the compiler to use code from UIKit.
  • Then, there’s a class declaration. It tells the compiler: this is the class we’re creating and we want it to extend UIViewController. When developing apps for iOS, everything you do is object-oriented. All functionality of an app resides in one or more classes. This class called MainViewController holds the code for our interface, and it’s connected to the .xib file. And the class extends UIViewController, which means that we’ll make use of the code Apple wrote for the superclass UIViewController and add our own code to it. Our code, the UIViewController superclass, and the MainViewController.xib file make up the single interface of our app.
  • Inside the squiggly brackets, we write the contents of this class.
  • Then inside the class, there’s methods like viewDidLoad(). This method is called when the MainViewController.xib file is loaded into memory. We use it to set up the view.

Writing the first method: generateRandomNumber()

Let’s create our first method. It’s called generateRandomNumber and it returns a random number of 4 digits, just what we need for our little game!

This is the entire method:

func generateRandomNumber() -> String
{
    var result:String = ""

    for _ in 1...4
    {
        var digit:Int = Int(arc4random_uniform(8) + 1)

        result += "\(digit)"
    }

    return result
}

And go over it line by line:

  1. First, we write func, and then generateRandomNumber, and then (), and then -> String. We declare our method by writing func, and then set its name to generateRandomNumber. Then, we say that this method has no parameters by writing (). If our method had parameters, we would have written (parameter1:String) for example. Then we set the return value of this method, by writing a single arrow -> and writing the return type String. It means that, whatever may happen, this method must return a String.
  2. Then, we declare and initialize a new variable called result with type String and value "" (empty string).
  3. Then, we write a for-loop. Our loop is supposed to repeat itself 4 times, hence the 1...4. The underscore _ means that we don’t want to keep track of how many times this loop has run, inside the loop.
  4. Then, inside the loops squiggly brackets { and } we write the contents of the loop. We declare and initialize a variable called digit of type Int, that has the value of Int(arc4random_uniform(8) + 1). The function arc4random returns a random value from 0 to 7. That’s 0 or 1 or 2 etc. up to 7 (not 8!). Then, we add 1 to it to always have a value from 1 to 8 (0-7 -> 1-8).
  5. Then, we append the string value of digit to result. Do you notice that result is a String while digit is an Int? We can’t add an integer to a string, that’s why we interpolate the Int inside a string. It’s a quick and dirty way to turn just about anything into a String, by using the "\(...)" notation.
  6. In the end, we return result. Like we declared, the method must always return a String value.

Connecting code with UI: IBOutlet

In order to use the interface elements we created with Interface Builder inside the MainViewController.xib, we must create a connection between the controller class file and the XIB. Such a connection is called an outlet, and the statement to create an outlet goes like this:

@IBOutlet weak var numbersLabel:UILabel?
@IBOutlet weak var scoreLabel:UILabel?
@IBOutlet weak var inputField:UITextField?

This is what happens:

  1. First, we start with @IBOutlet this is a special declaration statement that indicates that the property we’re creating is in fact an outlet. A property is just an instance variable (like we created earlier), except that it’s also available for use outside of a class. For now, let’s leave it at that.
  2. Then, we write weak var. That means that this property is weak, as opposed to strong. Weak means that whenever our controller class is removed from memory, the property can be removed at the same time.
  3. Then, we write the property name and type, ex. numbersLabel of type UILabel.
  4. Finally, we indicate that the property is an optional, so it can be nil, written with the question mark ? at the end of the declaration.

Connecting the outlet in Interface Builder

Now, go to MainViewController.xib in Interface Builder. Here’s how you connect the property to the outlet.

  1. Click the first UILabel, the one in the middle of the screen that says “1234”.
  2. Hold the Control-key.
  3. Click-and-drag from File’s Owner (Document Outline, under Placeholders) to the UILabel with “1234”. A blue line should be visible.
  4. Release the mouse when at the label, then a black gizmo should appear.
  5. Select the right outlet: numbersLabel.

Repeat the same step for the score and the textfield. Now you’ve made a connection between the code and the interface, for specific elements and properties.

Watch the video to see how to create the outlets.

Creating 2 more methods: updateScoreLabel() and setRandomNumberLabel()

Switch back to the MainViewController.swift class file and add these two methods, right above the generateRandomNumber method we wrote earlier.

func updateScoreLabel()
{
    scoreLabel?.text = "\(score)"
}

func setRandomNumberLabel()
{
    numbersLabel?.text = generateRandomNumber()
}

What do these two methods do?

  1. updateScoreLabel first checks if the property scoreLabel, connected to the outlet for the label with the score, is nil. It’s an optional property, so it could be empty. The code does that with a technique that’s called optional chaining, denoted by the question mark: ?. When scoreLabel is nil, any code behind the question mark isn’t executed! Then, it sets the text property of the label to "Score: \(score)", which is another string interpolation of the score instance variable.
  2. setRandomNumberLabel sets the numbersLabel with a random number, by first checking whether numbersLabel is not nil (using optional chaining) and then setting numbersLabel!.text to the return value of method generateRandomNumber().

Instance variable: keeping the score

Then, create another instance variable just below the outlets you created earlier.

Like this:

var score:Int = 0

See how this is different from a property or an outlet? It’s just a variable that’s declared in the scope of the class, and not in the scope of a method.

Setting up viewDidLoad()

Now, let’s quickly fill the viewDidLoad method with some code. The viewDidLoad method is overridden with the override statement, just before the func statement. Do you see it? It means that the superclass UIViewController of our class MainViewController has a method with the same name, and we overwrite it with new functionality. Whenever this method is called in the app lifecycle, our method is called, and not the method of the superclass. This allows us to customize the behaviour of the controller and the interface, and hooking into the view lifecycle that the UIViewController has.

This is the code for the method viewDidLoad:

super.viewDidLoad()

setRandomNumberLabel()
updateScoreLabel()

inputField?.addTarget(self, action: #selector(textFieldDidChange(textField:)), for:UIControlEvents.editingChanged)

And this is what happens:

  1. First, we call super.viewDidLoad(). This is needed to ensure that the view lifecycle is not interrupted. It’s a call to the viewDidLoad superclass method, and it’s required.
  2. Then, we call setRandomNumberLabel() and updateScoreLabel(). Can you find out what this does? It sets the label in the interface to a random number, and updates the score with the initial value of 0. We set that initial value when declaring the instance variable score, at the top of the class.
  3. Then, we check if optional inputField not is nil using optional chaining. The property inputField is connected to the outlet of the big textfield in the middle of the screen, in our interface. We add a target for an event, that calls an action.

The target, MainViewController, is indicated by self. It’s self-explanatory: self means the currect context, so it means this current class.

The action that’s called is denoted by #selector(textFieldDidChange(textField:)). It’s the name of the method that should be called when the event UIControlEvents.editingChanged happens. We’ll write that method later on.

The event will be fired when the text inside the text field changes, so when you type something in it. For each character you type, it fires an event, and so it executes the method we just gave it.

What happens when we input text?

Take a look at this method, and then add it to your code:

func textFieldDidChange(textField:UITextField)
{
    if inputField?.text?.characters.count ?? 0 < 4
    {
        return
    }

    if  let numbers_text    = numbersLabel?.text,
        let input_text      = inputField?.text,
        let numbers = Int(numbers_text),
        let input   = Int(input_text)
    {
        print("Comparing: \(input_text) minus \(numbers_text) == \(input - numbers)")

        if(input - numbers == 1111)
        {
            print("Correct!")

            score += 1                
        }
        else
        {
            print("Incorrect!")

            score -= 1                
        }
    }

    setRandomNumberLabel()
    updateScoreLabel()
}

Can you figure out what happens here?

  1. First, we’re checking if the number of characters in inputField is smaller than 4. When that’s the case, we return the method: execution halts, so the code below return is not executed when the if-statement is true. (When inputField or inputField.text is nil, the character count is set to 0 thanks to the ?? operator.)
  2. Then, we check whether the inputField.text and numbersLabel.text are nil using optional binding with if let, because they’re optionals. Optional binding statements can be combined together with a comma. Each statement is executed consecutively, and when one of them fails (i.e. the variable involved is nil), execution of the if-statement is stopped and the code continues below the end of the statement. Once the text inside the text field is checked, the code attempts to convert these String variables to Int. If that succeeds, the code inside the if-statement (between the squiggly brackets) is executed.
  3. Inside the if-statement, we compare the input value to the random value. Remember the point of our game? You were supposed to add one to each of the digits. Since we don’t include digits 0 and 9, you can easily figure out that the exercise is correct when the difference between the two values numbers and input is 1111.
  4. If the input is correct, up the score one point by writing score += 1, which means “add 1 to score“. If it’s wrong, subtract one point by writing score -= 1.
  5. Then, update the random number with a new value, update the score label, and empty the textfield value.
Got a killer app idea?

Grab the App Toolbox 2017 to learn how to save time building your app, and how to 10x your app installs in the App Store. With the toolbox, you’ll immediately know how to move forward to build better, more profitable apps.

Get The App Toolbox

Voila!

And there you have it, a running game! Run the app by hitting Command-R and see if you can play it. Encounter any errors? Ask for help in the comments, and backtrace your steps in case you missed something.

Run the app!

Let’s see where this got us. Run the app, and try out the functionality. If you followed closely, your app should do this:

  • Not remove the input code when 4 characters have been entered
  • Still check the code for validity
  • Allow no more than 4 characters

All thanks to delegation! Lets move on and see how we can make this game nicer.

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

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!

Most Popular Content

Written By: Reinder de Vries

Reinder de Vries is an indie app developer who teaches aspiring app developers and marketers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed over 50 apps for iOS, Android and the web, and his code is used by millions of users all over the globe. When Reinder isn't building apps, he enjoys strong espresso and traveling.

Got a killer app idea?

Grab the App Toolbox 2017 to learn how to save time building your app,
and how to 10x your app installs in the App Store. With the toolbox, you'll immediately know how to move forward to build better, more profitable apps.

Get The App Toolbox

Comments & Thoughts


Leave a Reply

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

  • Reinder de Vries (May 10, 2017)

    @Tim: Awesome! Glad you like it :-) Thanks!

  • Tim (May 10, 2017)

    Reinder, This is an amazing tutorial! I have always wondered what the code means that i have been copying from other authors. But now I actually get a grasp on the syntax that guides the code. Thank you very much!!

  • Reinder de Vries (February 6, 2017)

    Kevin, check in the XIB of MainViewController if there are any orphaned outlet connections. This error occurs if you've made an outlet connection in Interface Builder, and then remove the property from the Swift class. You can also remove all outlets in Interface Builder, and then add them again. Make sure that all outlets are associated with the right properties.

    That warning simply means that var digit ... might as well be let digit ... – a constant. You can either ignore it, or change "var" to "let"

  • Kevin Lee (February 6, 2017)

    Hello,
    When I try to launch the app, stops in AppDelegate.swift on following line with given message.

    class AppDelegate: UIResponder, UIApplicationDelegate{ Thread 1: signal SIGABRT

    Below is the message on the Output window below.

    2017-02-06 21:43:55.035 Add-1[1930:148299] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Add_1.MainViewController 0x7fa918603730> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key inputLabel.'

    And a warning in MainViewController.swift

    func generateRandomNumber() -> String
    {
    var result:String = ""

    for _ in 1...4
    {
        var digit:Int = Int(arc4random_uniform(8) + 1)       Variable 'digit' was never mutated; consider changing to 'let' constant
    
        result += "\(digit)"
    }
    
    return result
    

    }

  • Jye Disisto (July 9, 2016)

    HELP?

  • Jye Disisto (July 9, 2016)

    Yeah I'm fairly sure i added the label to the interface builder?? https://uploads.disquscdn.com/images/a491480658f28c3476ca3f1f9c516103c647747dde0f3698268b2cf443db6897.png

  • Reinder de Vries (July 8, 2016)

    Did you add the label to the Interface Builder file? Did you connect the label to an outlet in the Swift file? Are you setting the label.text property in your code?

  • Jye Disisto (July 8, 2016)

    when i launch my app.. how come the numbers label doesn't show up??? Anyone know.

    Thanks

  • Reinder de Vries (June 18, 2016)

    Awesome, well done!

  • Joci Punk (June 18, 2016)

    Ok, I solved it. I didn't change the class.

  • Joci Punk (June 18, 2016)

    Hey, I try to do the outlets, but I do everything like you, and my outlets don't show up in the XIB. Idea?

  • Reinder de Vries (June 17, 2016)

    Hey Marco,

    Where do you have that code from? This looks like Swift 1 or 1.2, whereas the current "Add 1" code guide is written in Swift 2. For instance the "count" function is now:

    if(inputField?.text?.characters.count < 4)
    {
    return;
    }

    Moreover, you have a squiggly closing bracket "}" too much, right above textFieldDidChange. Also, which version of Xcode are you using? Don't use the beta Xcode 8 / beta Swift 3 just yet.

  • Marco Sanchez (June 17, 2016)

    Hi I am having trouble in my code and I think that I am missing something. Could someone please look over it?

On The Blog