Creating A Simple iOS Game With Swift In Xcode (Part 1)

Written by: Reinder de Vries, February 26 2015, in App Development, App Projects

Updated for Xcode 9 and Swift 4.0

Aw yiss! It’s app makin’ time. Fire up your Xcode, get your Swift hat on and get hacking with this game called Add-1.

During the coming days, you’ll be learning how to create a game for iOS with Swift. We’ll dive in Xcode, variables, working with input and output, optionals, using Interface Builder, all you need to get started with iPhone app coding.

Add 1

Creating A Simple iOS Game With Swift In Xcode

The game we’ll create is called “Add 1”, and as far as I know it’s an invention of Daniel Kahneman. He’s the author of “Thinking Fast and Slow”, and used the game as an assignment in his research of cognitive strain.

The game is perfect for creating a small and simple app with enough functionality to make it a worthwhile learning experience. By the end of this mini course, you’ll know how to make a simple app and you’ll be able to challenge your friends to see who can make the most add-1’s in 60 seconds.

Prerequisites

There’s not much to setup before you can follow this mini course, but you at least need:

  1. A Mac
  2. With Xcode 8 installed
  3. An hour or so of time in total
  4. No programming experience required!

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:

Unzip, and save in a convenient folder.

This project makes use of the following free assets:

Grab My Free iOS Development Course

Get complementary access to my course, Zero to App Store, and learn how you can build a real-time chat app with Firebase and Swift!

Yes, Send Me The Free Course!

Let’s get hacking!

To get started, set up Xcode for this project:

  1. Start Xcode
  2. Create a new project with File -> New -> Project... or Command-Shift-N.
  3. Pick Single-View Application
  4. Choose for Product Name: Add1
  5. Choose for Organization Name: LearnAppMaking
  6. Organization Identifier: com.learnappmaking
  7. Language: Swift, Devices: Universal or iPhone
  8. Click Next and pick a project location
  9. Click Create

Removing the default options

The project type Single-View Application comes with a few options we don’t need for our game, like Storyboards. Let’s remove some of those options to create an easier to work with environment.

  1. Go to the Project Navigator. It’s in the left pane, under the tab with the directory icon.
  2. Click on the big bar up top, where it says “Add 1, 2 targets”. These are the project’s settings.
  3. In the main view, pick “Add 1” under Targets. It’s right under Project.
  4. In the General tab, uncheck Landscape Left and Landscape Right for Device Orientation.
  5. Check Hide status bar
  6. For Main Interface, remove what’s in the selection input box, it must be emtpy.

Then, do this: From the Project Navigator, remove the files Main.storyboard by right-clicking and picking Delete.

Creating MainViewController

We’re going to create a new view controller. A view controller is a Swift component that governs what’s on the screen, it’s the code behind the interface. Usually, a view controller consists of a Swift class (based on UIViewController) and a XIB file.

Create a new view controller by doing:

  1. Right-click on the project in Project Navigator. That’s the big bar up top.
  2. Choose New File....
  3. Choose Cocoa Touch Class.
  4. For Class, type in MainViewController.
  5. Make sure it’s a subclass of UIViewController.
  6. Tick the box Also create XIB file.
  7. Make sure it’s for iPhone, and with Swift.
  8. When Xcode asks for a location, choose the default directory or your project’s base directory.

Then, click the file MainViewController.xib from the Project Navigator. Xcode will switch to Interface Builder, the program that’s used to create interfaces. It’s an integral part of Xcode and you’ll use it a lot when creating iOS apps.

Interface Builder is a sort of scaffolding tool, because you can’t create functional interfaces for apps, but you create the basic setup that is needed for the interfaces of your app. Technically, you could create apps entirely from code, without making use of Interface Builder. Using IB will often improve your app making productivity, and it’s a great visual tool for app creation.

Since iOS 7, Interface Builder has a new feature called Auto Layout. It’s a helper tool that allows you to give interface elements constraints.

Say you add a button to your iPhone app UI. What happens when the iPhone is rotated from portrait to landscape orientation? Does your button resize, center, stretch, grow bigger — you set that with Auto Layout. The same goes for making a UI that works well on both iPhone and iPad, with different screen resolutions.

Creating the UI in Interface Builder

We’ll now create the interface for our app. Or better said: we’ll set up the structure. It’s a “dead” interface, it doesn’t do anything yet. Such a foundation is made with Interface Builder.

Go to MainViewController.xib in Interface Builder, by clicking on the file in the Project navigator. Then, have a look at the screenshot below.

This is Interface Builder. On the left you see the list of items you’ve added to the UI of your app. For you, it’s empty of course: we haven’t added anything yet. Whenever you add an interface element, you drag it from the bottom-right list to the middle main part of Interface Builder. You can then change the elements (buttons, labels, pickers, etc.) with the gizmos on the right. These gizmos are called inspectors, and they govern the properties of each of the elements.

The list on the left (called Document Outline) is a hierarchical list of all elements on the screen, and 2 special items: File’s Owner and First Responder. We’ll be using the File’s Owner later on.

We’ll now set up the views and layout of the game. You need the following metrics to properly set everything up — make sure you watch the video!

Views

  • Background Image View
    • Full Size, Aspect Fill
  • Score Image
    • Top Left, 149x50
  • Score Label
    • On Score Image, “1234”, Font: 22, Regular, HVD Comic Serif Pro
  • Time Image
    • Top Right, 149x50
  • Time Label
    • On Time Image, “01:00”, Font: 22, Regular, HVD Comic Serif Pro
  • Number Image
    • Top Center, 302x129
  • Number Label
    • Center at Number Image, “1234”, Font: 70, Regular, HVD Comic Serif Pro, Alignment Center
  • Text Field
    • Center Below Number, input Background, Font: 70, Regular, HVD Comic Serif Pro, Border Style “None”, Keyboard Type “Number Pad”, Alignment Center
  • Explanation Label:
    • Center Bottom, Font: 70, Regular, HVD Comic Serif Pro, 2 Lines, text: “Add 1 to each of the digits. So, 1357 becomes 2468.”

Colors

  • White
  • Brown (RGB): 135, 79, 33
  • Blue (RGB): 105, 168, 255
Watch the video to see how to create the interfaces of the app.

Setting up the app starting-point: AppDelegate

When an app starts, the function application(_:didFinishLaunchingWithOptions:) is called. It sets up the application and gives it a starting point for the first interface. When using Storyboards, you don’t really need this function, because Xcode already knows the first storyboard it should use at app launch. We however don’t use Storyboards, so we need to tell the app what it should show when it’s launched.

First, add this instance variable to the AppDelegate class:

var mainVC:MainViewController?

You write that at the top of the class, so right after the first { of the file. It’s inside the AppDelegate class. We’ve just told the compiler: we want to use a variable called mainVC of type UIViewController (optional) and it should be available in the scope of the entire class. Telling the compiler what variables to use, and which type and which name, is called declaring or declaration.

Then, replace the code inside the function application(_:didFinishLaunchingWithOptions:) , inside the squiggly braces { and }, with this code:

mainVC = MainViewController(nibName: "MainViewController", bundle:nil)

let frame = UIScreen.main.bounds
window = UIWindow(frame: frame)

window!.rootViewController = mainVC
window!.makeKeyAndVisible()

return true

This is what our code does:

  1. Initialize the instance variable mainVC by calling constructor method MainViewController with 2 parameters: “MainViewController” for the nibName and nil for the bundle. We just said: set up variable mainVC and fill it with the contents of our MainViewController.xib file.
  2. Then, create a constant frame with value UIScreen.main.bounds. We store the screen resolution of the app inside constant frame. A constant is a variable with a fixed value, so it never changes. Just like the dimensions of the iPhone screen never changes, because it’s a physical object.
  3. Then, initialize the instance variable window by calling constructor method UIWindow on it. This method takes one parameter: frame, the constant we set up earlier. It’s a named parameter, because you write frame: frame. The first frame is the name of the parameter, the second frame is the variable (a constant in this case) we supply as the parameter.
  4. Then, we set mainVC to be the rootViewController of window. We use the exclamation mark to force unwrap the variable window. The instance variable window is an optional, which means it could be nil. In order to use it as a definitive variable (a variable that is not nil), we need to unwrap it. In this case, we can be certain that it’s not nil because we’ve just initialized it. So, we force it to be a definitive non-optional variable by putting an exclamation mark at the end of the variable name.
  5. Then, we call a method makeKeyAndVisible() (no parameters) on the force unwrapped instance variable window.
  6. Then, we return true. This is required in the method application(_:didFinishLaunchingWithOptions:).
Grab My Free iOS Development Course

Get complementary access to my course, Zero to App Store, and learn how you can build a real-time chat app with Firebase and Swift!

Yes, Send Me The Free Course!

Run the app!

Alright, let’s run the app. Either:

  1. Click the Play button in the top-left corner of Xcode.
  2. Hit Command-R

When nothing happens, you might have made an error somewhere. Feel free to ask a question in the comments of this post. Also, check if you set the right Build Target (iPhone Simulator). Pick an iPhone model to use in the Simulator by using the dropdown list on the right of the Play button.

When the app runs, you should see your interface pop up on the screen. It doesn’t really do anything though!

If you don’t see anything or encounter an error, check whether you’ve set up the rootViewController the right way and whether you removed the Storyboard from both Xcode and the project settings.

See you next time!

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

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.

Grab My Free iOS Development Course

Get complementary access to my course, Zero to App Store, and learn how you can build a real-time chat app with Firebase and Swift!

Yes, Send Me The Free Course!

Comments & Thoughts


  • Jup! Good catch :-). This is because the text field is still active “behind” the modal dialog. When you input text, textFieldDidChange is executed. It’ll compare the input and the random number, and mark it as wrong because it’ll never match. You can either change the first conditional in textFieldDidChange to return when the input > 4 characters, or change showHUDWithAnswer as follows:

    Add the following line right below hud?.show(animated: true)

    inputField?.isEnabled = false
    

    Then, inside the async closure, add this at the end:

    self.inputField?.isEnabled = true
    self.inputField?.becomeFirstResponder()
    

    This will disable the input field when the dialog hud shows, and then put the focus back into the input field when the hud disappears. The entire last conditional now looks like this:

    if(imageView != nil)
    {
        hud?.mode = MBProgressHUDMode.customView
        hud?.customView = imageView
    
        hud?.show(animated: true)
    
        inputField?.isEnabled = false
    
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            self.hud?.hide(animated: true)
            self.inputField?.text = ""
    
            self.inputField?.isEnabled = true
            self.inputField?.becomeFirstResponder()
        }
    }
    
  • Jon Perrault

    I noticed that after a new random number appears and the thumbs up is still there if you type anything into the box at that exact point, it skips to another number and marks it wrong. Is there anyway to fix this?

  • OK! If you put “print(#function)” (no quotes) at the top of viewDidLoad() in MainViewController.swift, do you see the name of the method show in the debugger window when you run your app? If not, you should check whether you removed “Main” from the project settings. It’s explained in the first part of the video.

  • Lucas Dickson

    Thanks! that fixed the error but when ever i run the app its showing a white screen

  • Gotcha! You’re missing a “-> Bool” at the end of application(didFinishLaunchingWithOptions:) method. Also, the “@nonobjc” keyword isn’t necessary. Change it to this:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
    
  • Lucas Dickson
  • Lucas Dickson

    After typing return true it says its an unexpected non void return value in void function

  • Yes Justin, they were! Check out the 3-series links right below the chapter “Project Code, Assets and This Series” (at the top of the page). Happy coding!

  • Justin

    Were subsequent videos ever published (Weeks 2 and 3)?

  • Hi Martin,

    OK. Could be the constraints, yes. Are you seeing any errors or constraint warnings when editing the XIB in Interface Builder? Errors and warnings show up at the top right corner of the list of UI elements. Also, make sure you’ve connected the outlet correctly, and that you’re setting a value with code in the Swift file.

    Are you using the stable Xcode 7 or a beta of Xcode 8?

  • Martin

    Hey, I’m running the app and for some reason the 1234 in brown is not displaying when I run the simulator. would this be an issue with the constraints? It shows in the MainViewController, just not when I run the sim. Help please :-)

  • That error message isn’t an error, it usually appears in the Simulator for no good reason. The reason the keyboard doesn’t show up is because you probably haven’t called becomeFirstResponder on the input field. Make sure you follow the video by the letter, otherwise you’ll run into issues like these.

  • Jye Disisto

    I fixed previous issues. But now I’ve noticed that when i launch the app. The iPhone numeric pad doesn’t pop up…. and below I’ve pasted the error message.

    2016-07-09 11:55:57.299 Add1[5686:468215] Can’t find keyplane that supports type 4 for keyboard iPhone-PortraitChoco-NumberPad; using 1336863583_PortraitChoco_iPhone-Simple-Pad_Default

  • OK, that most definitely means you either have the outlets set up wrong or there’s not a proper connection between the Interface Builder file and the Swift file. This is explained in the video, so make sure you double check that!

  • Max Cordell

    Ok so i think that fixed that problem but now i’m getting this.
    2016-07-03 16:47:40.752 add1[1994:42691] *** Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: ‘[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key view.’
    Thanks again!

  • Alright, got it. You need to go to your project’s settings by clicking on the top item in the Project Navigator (the blue one), and then go the General tab, and then remove the text from “Main Interface”. The app now thinks you want to start with the Main Storyboard, when in fact you’ve coded it to start with the first view controller in the AppDelegate. This is all explained in the beginning of the video, so make sure you watch that too.

  • Max Cordell

    I think this is it.
    2016-07-03 08:10:40.657 add1[22262:939997] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘Could not find a storyboard named ‘Main’ in bundle NSBundle (loaded)’
    Thanks so much!

  • In the bottom right area, the one with the bold black text (the Debug Area), what does the exception say? It’s usually at the top of all the text, like NSInconsistencyException bla bla bla. Let me know what that is, and we’ll figure it out!

  • Max Cordell

    help me i got a sigabrt error.

  • Thanks very much David! Your questions about programming and interest in coding apps helps fuel LearnAppMaking, so if you do have a question about coding — help me help you ;-)

  • David Pham

    Thank you SO much for this! I am new to programming and this helped me understand the overwhelming Xcode UI. How can I help support you?! :) Thank you again!!

  • Could you compare your code of AppDelegate.swift with the code from week 1? Perhaps you’ve missed something. A SIGABRT is a pretty generic error, so it could be just about anything.

  • Mari Vijil

    I need help really Bad!!!! I did week 1 two TIMES
    and I get the same error: Thread 1: signal SIGABRT

  • James Ikeler

    Hey,
    I’m been working on my own app(Not using your code at all).And I used your assets for my app.Can I use them if I were to publish them to the app store I would leave credit to the website and stuff.But if I can’t can you tell me who made them.

  • Hiya! Leuk om van je te horen :-)

    You’re gonna wanna keep an eye on the Swift and Xcode version numbers, then. Right now the most recent version is Swift 2.2 and Xcode 7.3, but they’re getting ready (3-4 months) to release Swift 3. All of our paid courses are kept up-to-date the minute a new version or a change comes out.

    As it so happens, the “Add 1” guide is updated for Swift 2.2. I know how frustrating it can be to check out an answer on StackOverflow, and then realize it only works on Swift 1.2… You’ll get the hang of it with practice :-).

    Keep coding!

  • Reinder!!!! nice tutorial man, ik ben een Nederlander maar woon nu in Florida, i’m just starting to learn app development. Its really hard because every tutorial i find online seems to be out of date overtime there is an Xcode update

  • The Project Navigator should show a file that’s called “Assets.xcassets”. It’s icon is a blue folder. Open it, then drag all the files from Finder to the list of files in the assets window.

  • Thanks. Could you share a screenshot with the File’s Owner selected, and then the Connections Inspector open? First click File’s Owner, then click the icon on the far right, the one with the circle and an arrow in it. It’ll show what you set the outlets to.

  • dylan

    How do you import the background and other images i can’t seem to find them i have Xcode 7.3

  • Noah1955

    very cool!

  • That’s a really weird error! Where did you put the extra semi colon? Glad it’s solved now :-)

  • Arian Nasser

    Just fixed my issue by removing the UIwindow semi colon , :)

  • If you could send a screenshot of the outlets, that’d be awesome. First click File’s Owner, then the Connections Inspector on the far right (circle with the arrow).

  • Arian Nasser

    Screen shots

  • Arian Nasser

    just finished the first part , and then when i tried to run it this happens. i’ve checked everything honestly everything was ok

  • At what point in the code guide are you?

    My guess is you should check the outlets on ViewController, if you set any. Click on “First Responder” in Interface Builder, then go to the Connections Inspector, and check that every UI element has an outlet assigned to it and no connections are “dangling” / orphaned. This can happen when you make an outlet connection and then change the name of the property, or remove it.

    Good luck :-)

  • Arian Nasser

    I am getting this error , What should i do? Every time i try to run it happens , please help

  • Does it say anything in the Debug Window? It’s pointing towards AppDelegate.swift because SIGABRT is a runtime crash, but the cause could be pretty much anywhere. Did you check all the optionals, i.e. if they’re unwrapped properly and not accidentally nil when force-unwrapped?

  • Edmond Hobeika

    Everything is solved now.

    Just the app is not running. Seems from the AppDelegate.swift. is says on the class name “Thread 1 – signal SIGABRT”

  • Edmond Hobeika

    I get this when i run the app

    “libc++abi.dylib: terminating with uncaught exception of type NSException”

  • Edmond Hobeika

    I just solved the “inputField!.text.characters.count < 4 || numbersLabel!.text.characters.count < 4"

    It should be
    "inputField!.text?.characters.count < 4 || numbersLabel!.text?.characters.count < 4"

    But i am still having issues with "textFieldDidChange:"

    The app is not running
    it crashes

  • Edmond Hobeika

    I’m still getting errors on “textFieldDidChange:” and “inputField!.text.characters.count < 4 || numbersLabel!.text.characters.count < 4"

  • Yeah, my bad, inputField is an optional, so it must be unwrapped. You can use force unwrapping, because you’re already checking whether inputField is accidentally nil. Change it for: inputField!.text.characters.count.

    If you’re unfamiliar with optionals, make sure to do a little reading on them or check out our Pro Course — that’s got it covered in great detail. See: https://learnappmaking.com/pro-course

  • You’re missing a colon, it is: “textFieldDidChange:”

  • Edmond Hobeika

    I even get an error here

  • Edmond Hobeika

    check

  • Edmond Hobeika

    the inputField.text.characters.count < 4 is not giving me an error..

  • Replace “println” with “print”, “score–” with “score -= 1”, “score++” with “score += 1”, and “count” doesn’t exist any more, so replace it with “inputField.text.characters.count < 4".

    By the way, you might want to change your font to a monospace one, it's way easier to read than the font you're using now.

  • Edmond Hobeika

    Screenshot below

  • Edmond Hobeika

    I am getting this error.

    Please help.

    Thanks

  • Did you create both the Swift class file and the XIB? I can only see the XIB file in the screenshot you sent, so most likely the class “MainViewController” is missing. See if you can delete the XIB file and then follow the steps from chapter “Creating MainViewController” to create both the XIB and the Swift class file.

    Good luck!

  • Daniel Qeli

    Like this

  • Daniel Qeli

    What should I do if it says MainViewController is an unresolved identifier while testing the app near the middle?

  • You’re absolutely right! That’s Swift < 1.2, thanks for pointing it out :-).

    This should help you:

    if(inputField == nil || numbersLabel == nil || count(inputField!.text) < 4 || count(numbersLabel!.text) < 4)