Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon

The Swift Programming Language

Save for later
  • 25 min read
  • 06 Oct 2015

article-image

This article is by Chuck Gaffney, the author of the book iOS 9 Game Development Essentials. This delves into some vital specifics of the Swift language.

(For more resources related to this topic, see here.)

At the core of all game development is your game's code. It is the brain of your project and outside of the art, sound, and various asset developments, it is where you will spend most of your time creating and testing your game. Up until Apple's Worldwide Developers Conference WWDC14 in June of 2014, the code of choice for iOS game and app development was Objective-C. At WWDC14, a new and faster programming language Swift, was announced and is now the recommended language for all current and future iOS games and general app creation.

As of the writing of this book, you can still use Objective-C to design your games, but both programmers new and seasoned will see why writing in Swift is not only easier with expressing your game's logic but even more preformat. Keeping your game running at that critical 60 FPS is dependent on fast code and logic. Engineers at Apple developed the Swift Programming Language from the ground up with performance and readability in mind, so this language can execute certain code iterations faster than Objective-C while also keeping code ambiguity to a minimum. Swift also uses many of the methodologies and syntax found in more modern languages like Scala, JavaScript, Ruby, and Python.

So let's dive into the Swift language.

It is recommended that some basic knowledge of Object Oriented Programming (OOP) be known prior but we will try to keep the build up and explanation of code simple and easy to follow as we move on to the more advanced topics related to game development.

Hello World!

It's somewhat tradition in the education of programming languages to begin with a Hello World example. A Hello World program is simply using your code to display or log the text Hello World. It's always been the general starting point because sometimes just getting your code environment set up and having your code executing correctly is half the battle. At least, this was more the case in previous programming languages.

Swift makes this easier than ever, without going into the structure of a Swift file (which we shall do later on and is also much easier than Objective-C and past languages), here's how you create a Hello World program:

print("Hello, World!")

That's it! That is all you need to have the text "Hello, World" appear in XCode's Debug Area output.

No more semicolons

Those of us who have been programming for some time might notice that the usually all important semicolon (;) is missing. This isn't a mistake, in Swift we don't have to use a semicolon to mark the end of an expression. We can if we'd like and some of us might still do it as a force of habit, but Swift has omitted that common concern.

The use of the semicolon to mark the end of an expression stems from the earliest days of programming when code was written in simple word processors and needed a special character to represent when the code's expression ends and the next begins.

Variables, constants, and primitive data types

When programming any application, either if new to programming or trying to learn a different language, first we should get an understanding of how a language handles variables, constants, and various data types, such as Booleans, integers, floats, strings, and arrays. You can think of the data in your program as boxes or containers of information. Those containers can be of different flavors, or types. Throughout the life of your game, the data could change (variables, objects, and so on) or they can stay the same.

For example, the number of lives a player has would be stored as a variable, as that is expected to change during the course of the game. That variable would then be of the primitive data type integer, which are basically whole numbers. Data that stores, say the name of a certain weapon or power up in your game would be stored in what's known as a constant, as the name of that item is never going to change. In a game where the player can have interchangeable weapons or power-ups, the best way to represent the currently equipped item would be to use a variable. A variable is a piece of data that is bound to change. That weapon or power-up will also most likely have a bit more information to it than just a name or number; the primitive types we mentioned prior. The currently equipped item would be made up of properties like its name, power, effects, index number, and the sprite or 3D model that visually represents it. Thus the currently equipped item wouldn't just be a variable of a primitive data type, but be what is known as type of object. Objects in programming can hold a number of properties and functionality that can be thought of as a black box of both function and information. The currently equipped item in our case would be sort of a placeholder that can hold an item of that type and interchange it when needed; fulfilling its purpose as a replaceable item.

Swift is what's known as a type-safe language, so keeping track of the exact type of data and even it's future usage (that is, if the data is or will be NULL) as it's very important when working with Swift compared to other languages. Apple made Swift behave this way to help keep runtime errors and bugs in your applications to a minimum and so we can find them much earlier in the development process.

Variables

Let's look at how variables are declared in Swift:

var lives = 3      //variable of representing the player's lives

lives = 1          //changes that variable to a value of 1

Those of us who have been developing in JavaScript will feel right at home here. Like JavaScript, we use the keyword var to represent a variable and we named the variable, lives.

The compiler implicitly knows that the type of this variable is a whole number, and the data type is a primitive one: integer.

The type can be explicitly declared as such:

var lives: Int = 3    //variable of type Int

We can also represent lives as the floating point data types as double or float:

// lives are represented here as 3.0 instead of 3

var lives: Double = 3          //of type Double

var lives: Float = 3          //of type Float

Using a colon after the variable's name declaration allows us to explicitly typecast the variable.

Constants

During your game there will be points of data that don't change throughout the life of the game or the game's current level or scene. This can be various data like gravity, a text label in the Heads-Up Display (HUD), the center point of character's 2D animation, an event declaration, or time before your game checks for new touches or swipes.

Declaring constants is almost the same as declaring variables.

Using a colon after the variable's name declaration allows us to explicitly typecast the variable.

let gravityImplicit = -9.8        //implicit declaration

let gravityExplicit: Float = -9.8 //explicit declaration

As we can see, we use the keyword let to declare constants.

Here's another example using a string that could represent a message displayed on the screen during the start or end of a stage.

let stageMessage = "Start!"

stageMessage = "You Lose!"  //error

Since the string stageMessage is a constant, we cannot change it once it has been declared. Something like this would be better as a variable using var instead of let.

Why don't we declare everything as a variable?

This is a question sometimes asked by new developers and is understandable why it's asked especially since game apps tend to have a large number of variables and more interchangeable states than an average application. When the compiler is building its internal list of your game's objects and data, more goes on behind the scenes with variables than with constants.

Without getting too much into topics like the program's stack and other details, in short, having objects, events, and data declared as constants with the let keyword is more efficient than var. In a small app on the newest devices today, though not recommended, we could possibly get away with this without seeing a great deal of loss in app performance. When it comes to video games however, performance is critical. Buying back as much performance as possible can allow for a better player experience. Apple recommends that when in doubt, always use let when declaring and have the complier say when to change to var.

More about constants

As of Swift version 1.2, constants can have a conditionally controlled initial value.

Prior to this update, we had to initialize a constant with a single starting value or be forced to make the property a variable. In XCode 6.3 and newer, we can perform the following logic:

let x : SomeThing

 

if condition

{

  x = foo()

}

else

{

  x = bar()

}

use(x)

An example of this in a game could be

let stageBoss : Boss

 

if (stageDifficulty == gameDifficulty.hard)

{

  stageBoss = Boss.toughBoss()

}

else

{

  stageBoss = Boss.normalBoss()

}

loadBoss(stageBoss)

With this functionality, a constant's initialization can have a layer of variance while still keeping it unchangeable, or immutable through its use. Here, the constant, stageBoss can be one of two types based on the game's difficulty: Boss.toughBoss() or Boss.normalBoss(). The boss won't change for the course of this stage, so it makes sense to keep it as a constant. More on if and else statements is covered later in the article.

Arrays, matrices, sets, and dictionaries

Variables and constants can represent a collection of various properties and objects. The most common collection types are arrays, matrices, sets, and dictionaries. An Array is an ordered list of distinct objects, a Matrix is, in short, an array of arrays, a Set is an unordered list of distinct objects and a Dictionary is an unordered list that utilizes a key : value association to the data.

Arrays

Here's an example of an Array in Swift.

let stageNames : [String] = ["Downtown Tokyo","Heaven Valley",
"Nether"]

The object stageNames is a collection of strings representing names of a game's stages. Arrays are ordered by subscripts from 0 to array length 1. So stageNames[0] would be Downtown Tokyo, stageNames[2] would be Nether, and stageNames[4] would give an error since that's beyond the limits of the array and doesn't exist. We use [] brackets around the class type of stageNames, [String] to tell the compiler that we are dealing with an array of Strings. Brackets are also used around the individual members of this array.

2D arrays or matrices

A common collection type used in physics calculations, graphics, and game design, particularly grid-based puzzle games, are two-dimensional arrays or matrices. 2D arrays are simply arrays that have arrays as their members. These arrays can be expressed in a rectangular fashion in rows and columns.

For example, the 4x4 (4 rows, 4 columns) tile board in the 15 Puzzle Game can be represented as such:

var tileBoard = [[1,2,3,4],

                [5,6,7,8],

                [9,10,11,12],

                [13,14,15,""]]

In the 15 Puzzle game, your goal is to shift the tiles using the one empty spot (represented with the blank String ""), to all end up in the 1—15 order we see up above. The game would start with the numbers arranged in a random and solvable order and player would then have to swap the numbers and the blank space.

To better perform various actions on AND or OR, store information about each tile in the 15 Game (and other games); it'd be better to create a tile object as opposed to using raw values seen here. For the sake of understanding what a matrix or 2D array is, simply take note on how the array is surrounded by doubly encapsulated brackets [[]]. We will later use one of our example games, SwiftSweeper, to better understand how puzzle games use 2D arrays of objects to create a full game.

Here are ways to declare blank 2D arrays with strict types:

var twoDTileArray : [[Tiles]] = []

//blank 2D array of type,Tiles

var anotherArray = Array<Array<Tile>>()

//same array, using Generics

The variable twoDTileArray uses the double brackets [[Tiles]] to declare it as a blank 2D array or matrix for the made up type, tiles. The variable anotherArray is a rather oddly declared array that uses angle bracket characters <> for enclosures. It utilizes what's known as Generics. Generics is a rather advanced topic that we will touch more on later. They allow for very flexible functionality among a wide array of data types and classes. For the moment we can think of them as a catchall way of working with Objects.

To fill in the data for either version of this array, we would then use for-loops to fill in the data. More on loops and iterations later in the article!

Sets

This is how we would make a set of various game items in Swift:

var keyItems = Set([Dungeon_Prize, Holy_Armor, Boss_Key,"A"])

This set keyItems has various objects and a character A. Unlike an Array, a Set is not ordered and contains unique items. So unlike stageNames, attempting to get keyItems[1] would return an error and items[1] might not necessarily be the Holy_Armor object, as the placement of objects is internally random in a set. The advantage Sets have over Arrays is that Sets are great at checking for duplicated objects and for specific content searching in the collection overall. Sets make use of hashing to pinpoint the item in the collections; so checking for items in Set's content can be much faster than an array. In game development, a game's key items which the player may only get once and should never have duplicates of, could work great as a Set. Using the function keyItems, contains(Boss_Key) returns the Boolean value of true in this case.

Sets were added in Swift 1.2 / XCode 6.3. Their class is represented by the Generic type Set<T> where T is the class type of the collection. In other words, the set Set([45, 66, 1233, 234]) would be of the type Set<Int> and our example here would be a Set<NSObject> instance due to it having a collection of various data types.

We will discuss more on Generics and Class Hierarchy later in this article.

Dictionaries

A Dictionary can be represented this way in Swift:

var playerInventory: [Int : String] = [1 : "Buster Sword", 43 :
"Potion", 22: "StrengthBooster"]

Dictionaries use a key : value association, so playerInventory[22] returns the value StrengthBooster based on the key, 22. Both the key and value could be initialized to almost any class type*. In addition to the inventory example given, we can have the code as following:

var stageReward: [Int : GameItem] = [:] //blank initialization

//use of the Dictionary at the end of a current stage

stageReward = [currentStage.score : currentStage.rewardItem]

*The values of a Dictionary, though rather flexible in Swift, do have limitations. The key must conform to what's known as the Hashable protocol. Basic data types like integer and string already have this functionality, so if you are to make your own classes or data structures that are to be used in Dictionaries, say mapping a player actions with player input, this protocol must be utilized first. We will discuss more about Protocols, later in this article.

Dictionaries are like Sets in that they are unordered but with the additional layer of having a key and a value associated with their content instead of just the hashed key. As with Sets, Dictionaries are great for quick insertion and retrieval of specific data. In IOS Apps and in web applications, Dictionaries are what's used to parse and select items from JSON (JavaScript Object Notation) data.

In the realm of game development, Dictionaries using JSON or via Apple's internal data class, NSUserDefaults, can be used to save and load game data, set up game configurations or access specific members of a game's API.

For example, here's one way to save a player's high score in an IOS game using Swift:

let newBestScore : Void =
NSUserDefaults.standardUserDefaults().setInteger(bestScore,
 forKey: "bestScore")

This code comes directly from a published Swift—developed game called PikiPop, which we will use from time to time to show code used in actual game applications.

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime

Again, note that Dictionaries are unordered but Swift has ways to iterate or search through an entire Dictionary.

Mutable or immutable collections

One rather important discussion that we left out is how to subtract, edit or add to Arrays, Sets, and Dictionaries, but before we do that, we should understand the concept of mutable and immutable data or collections.

A mutable collection is simply data that can be changed, added to or subtracted from, while an immutable collection cannot be changed, added to or subtracted from.

To work with mutable and immutable collections efficiently in Objective-C, we had to explicitly state the mutability of the collection beforehand. For example, an array of the type NSArray in Objective-C is always immutable. There are methods we can call on NSArray that would edit the collection but behind the scenes this would be creating brand new NSArrays, thus would be rather inefficient if doing this often in the life of our game. Objective-C solved this issue with class type, NSMutableArray.

Thanks to the flexibility of Swift's type inference, we already know how to make a collection mutable or immutable! The concept of constants and variables has us covered when it comes to data mutability in Swift. Using the keyword let when creating a collection will make that collection immutable while using var will initialize it as a mutable collection.

//mutable Array

var unlockedLevels : [Int] = [1, 2, 5, 8]

 

//immutable Dictionary

let playersForThisRound : [PlayerNumber:PlayerUserName] =
[453:"userName3344xx5", 233:"princeTrunks", 6567: "noScopeMan98",
211: "egoDino"]

The Array of Int, unlockedLevels can be edited simply because it's a variable. The immutable Dictionary playersForThisRound, can't be changed since it's already been declared as a constant; no additional layers of ambiguity concerning additional class types.

Editing or accessing collection data

As long as a collection type is a variable, using the var keyword, we can do various edits to the data. Let's go back to our unlockedLevels array. Many games have the functionality of unlocking levels as the player progresses. Say the player reached the high score needed to unlock the previously locked level 3 (as 3 isn't a member of the array). We can add 3 to the array using the append function:

unlockedLevels.append(3)

Another neat attribute of Swift is that we can add data to an array using the += assignment operator:

unlockedLevels += [3]

Doing it this way however will simply add 3 to the end of the array. So our previous array of [1, 2, 5, 8] is now [1, 2, 5, 8, 3]. This probably isn't a desirable order, so to insert the number 3 in the third spot, unlockedLevels[2], we can use the following method:

unlockedLevels.insert(3, atIndex: 2)

Now our array of unlocked levels is ordered to [1, 2, 3, 5, 8].

This is assuming though that we know a member of the array prior to 3 is sorted already. There's various sorting functionalities provided by Swift that could assist in keeping an array sorted. We will leave the details of sorting to our discussions of loops and control flow later on in this article.

Removing items from an array is just as simple. Let's use again our unlockedLevels array. Imagine our game has an over world for the player to travel to and from, and the player just unlocked a secret that triggered an event, which blocked off access to level 1. Level 1 would now have to be removed from the unlocked levels. We can do it like this:

unlockedLevels.removeAtIndex(0) // array is now [2, 3, 5, 8]

Alternately, imagine the player lost all of their lives and got a Game Over. A penalty to that could be to lock up the furthest level. Though probably a rather infuriating method and us knowing that Level 8 is the furthest level in our array, we can remove it using the .removeLast() function of Array types.

unlockedLevels.removeLast() // array is now [2,3,5]

That this is assuming we know the exact order of the collection. Sets or Dictionaries might be better at controlling certain aspects of your game.

Here's some ways to edit a set or a dictionary as a quick guide.

Set

inventory.insert("Power Ring")    //.insert() adds items to a set

inventory.remove("Magic Potion")  //.remove() removes a specific item

inventory.count                  //counts # of items in the Set

inventory.union(EnemyLoot)        //combines two Sets

inventory.removeAll()            //removes everything from the Set

inventory.isEmpty                //returns true

Dictionary

var inventory = [Float : String]() //creates a mutable dictionary

/*

one way to set an equipped weapon in a game; where 1.0 could represent the first "item slot" that would be placeholder for the player's "current weapon"

*/

inventory.updateValue("Broadsword", forKey: 1.0)

 

//removes an item from a Dictionary based on the key value

inventory.removeValueForKey("StatusBooster")

 

inventory.count                  //counts items in the Dictionary

inventory.removeAll(keepCapacity: false) //deletes the Dictionary

inventory.isEmpty                //returns false

 

//creates an array of the Dictionary's values

let inventoryNames = [String](inventory.values)

 

//creates an array of the Dictionary's keys

let inventoryKeys = [String](inventory.keys)

Iterating through collection types

We can't discuss about collection types without mentioning how to iterate through them in mass.

Here's some ways we'd iterate though an Array, Set or a Dictionary in Swift:

//(a) outputs every item through the entire collection

 //works for Arrays, Sets, and Dictionaries but output will vary

for item in inventory {

 print(item)

}

 

//(b) outputs sorted item list using Swift's sorted() function

 //works for Sets

for item in sorted(inventory) {

 print("(item)")

}

 

//(c) outputs every item as well as it's current index

//works for Arrays, Sets, and Dictionaries

for (index, value) in enumerate(inventory) {

print("Item (index + 1): (value)")

}

 

//(d)

//Iterate through and through the keys of a Dictionary

for itemCode in inventory.keys {

print("Item code: (itemCode)")

}

 

//(e)

//Iterate through and through the values of a Dictionary

for itemName in inventory.values {

 print("Item name: (itemName)")

}

As stated previously, this is done with what's known as a for-loop; with these examples we show how Swift utilizes the for-in variation using the in keyword. The code will repeat until it reaches the end of the collection in all of these examples. In example (c) we also see the use of the Swift function, enumerate(). This function returns a compound value, (index,value), for each item. This compound value is known as a tuple and Swift's use of tuples makes for a wide variety of functionality for functions loops as well as code blocks.

We will delve more into tuples, loops, and blocks later on.

Comparing Objective-C and Swift

Here's a quick review of our Swift code with a comparison of the Objective-C equivalent.

Objective-C

An example code in Objective-C is as follows:

const int MAX_ENEMIES = 10;  //constant

float playerPower = 1.3;    //variable

 

//Array of NSStrings

NSArray * stageNames = @[@"Downtown Tokyo", @"Heaven Valley", @" Nether"];

 

//Set of various NSObjects

NSSet *items = [NSSet setWithObjects: Weapons, Armor,

 HealingItems,"A", nil];

 

//Dictionary with an Int:String key:value

NSDictionary *inventory = [NSDictionary dictionaryWithObjectsAndKeys:

            [NSNumber numberWithInt:1], @"Buster Sword",

            [NSNumber numberWithInt:43], @"Potion",

            [NSNumber numberWithInt:22], @"Strength",

nil];

Swift

An example code in Objective-C is as follows:

let MAX_ENEMIES = 10          //constant

var playerPower = 1.3        //variable

 

//Array of Strings

let stageNames : [String] =
["Downtown Tokyo","Heaven Valley","Nether"]

 

//Set of various NSObjects

var items = Set([Weapons, Armor, HealingItems,"A"])

 

//Dictionary with an Int:String key:value

var playerInventory: [Int : String] =
[1 : "Buster Sword", 43 : "Potion", 22: "StrengthBooster"]

In the preceding code, we some examples of variables, constants, Arrays, Sets, and Dictionaries. First we see their Objective-C syntax and then we see the equivalent declarations using Swift's syntax. We can see from this example how compact Swift is compared to Objective-C.

Characters and strings

For some time in this article we've been mentioning Strings. Strings are also a collection of data type but a specially dealt collection of Characters, of the class type, String. Swift is Unicode-compliant so we can have Strings like this:

let gameOverText = "Game Over!"

We have strings with emoji characters like this:

let cardSuits = "♠ ♥ ♣ ♦"

What we did now was create what's known as a string literal. A string literal is when we explicitly define a String around two quotes "".

We can create empty String variables for later use in our games as such:

var emptyString = ""              // empty string literal

var anotherEmptyString = String() // using type initializer

Both are valid ways to create an empty String "".

String interpolation

We can also create a string from a mixture of other data types, known as string interpolation. String Interpolation is rather common in game development, debugging, and string use in general.

The most notable of examples are displaying the player's score and lives. This is how one our example games, PikiPop uses string interpolation to display current player stats:

//displays the player's current lives

var livesLabel = "x (currentScene.player!.lives)"

 

//displays the player's current score

var scoreText = "Score: (score)"

Take note of the "(variable_name)" formatting. We've actually seen this before in our past code snippets. In the various print() outputs, we used this to display the variable, collection, and so on we wanted to get info on. In Swift, the way to output the value of a data type in a String is by using this formatting.

For those of us who came from Objective-C, it's the same as this:

NSString *livesLabel = @"Lives: ";

int lives = 3;

NSString *livesText = [NSString stringWithFormat:@" %@
(%d days ago)", livesLabel, lives];

Notice how Swift makes string interpolation much cleaner and easier to read than its Objective-C predecessor.

Mutating strings

There are various ways to change strings. We can also add to a string just the way we did while working with collection objects. Here's a basic example:

var gameText = "The player enters the stage"

gameText += " and quickly lost due to not leveling up"

/* gameText now says

"The player enters the stage and lost due to not leveling up" */

Since Strings are essentially arrays of characters, like arrays, we can use the += assignment operator to add to the previous String.

Also, akin to arrays, we can use the append() function to add a character to the end of a string:

 let exclamationMark: Character = "!"

gameText.append(exclamationMark)

/*gameText now says "The player enters the stage and lost due to
not leveling up!"*/

Here's how we iterate through the Characters in a string in Swift:

for character in "Start!" {

    print(character)

}

//outputs:

//S

//t

//a

//r

//t

//!

Notice how again we use the for-in loop and even have the flexibility of using a string literal if we'd so like to be what's iterated through by the loop.

String indices

Another similarity between Arrays and Strings is the fact that a String's individual characters can be located via indices. Unlike Arrays however, since a character can be a varying size of data, broken in 21-bit numbers known as Unicode scalars, they can not be located in Swift with Int type index values.

Instead, we can use the .startIndex and .endIndex properties of a String and move one place ahead or one place behind the index with the .successor() and .predecessor() functions respectively to retrieve the needed character or characters of a String.

gameText[gameText.startIndex]              // = T

gameText[gameText.endIndex]                // = !

gameText[gameText.startIndex.successor()]  // = h

gameText[gameText.endIndex.predecessor()]  // = p

Here are some examples that use these properties and functions using our previous gameText String:

There are many ways to manipulate, mix, remove, and retrieve various aspects of a String and Characters. For more information, be sure to check out the official Swift documentation on Characters and Strings here: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html.

Summary

There's much more about the Swift programming language than we can fit here. Throughout the course of this book we will throw in a few extra tidbits and nuances about Swift as it becomes relevant to our upcoming gaming programming needs.

If you wish to become more versed in the Swift programming language, Apple actually provides a wonderful tool for us in what's known as a Playground.

Playgrounds were introduced with the Swift programming language at WWDC14 in June of 2014 and allow us to test various code output and syntax without having to create a project, build, run, and repeat again when in many cases we simply needed to tweak a few variables and function loop iterations.

There are a number of resources to check out on the official Swift developer page (https://developer.apple.com/swift/resources/).

Two highly recommended Playgrounds to check out are as follows:

  • Guided Tour Playground (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.playground.zip)

This Playground covers many of the topics we mentioned in this article and more, from Hello World all the way to Generics.

  • The second playground to test out is the Balloons Playground (https://developer.apple.com/swift/blog/downloads/Balloons.zip).

The Balloons Playground was the keynote Playgrounds demonstration from WWDC14 and shows off many of the features Playgrounds have to offer, particularly for making and testing games.

Sometimes the best way to learn a programming language is to test live code; and that's exactly what Playgrounds allow us to do.