Welcome to the second tutorial in this quick start guide to Swift. We’ll cover some of the concepts from the first part in more detail while also introducing more language features.
What you will learn…
- More detail regarding strings
- How to work with arrays and dictionaries
- Control flow with while loops and the switch statement
- How to work with enumerations
What you should know…
- A familiarity with at least one programming language
- The basics of the Swift programming language from part one
The primary focus of part two will be strings, collection types, control flow, and enumerations. We briefly looked at strings in part one but will spend more time with them here. We’ll also re-visit control flow, taking the time to examine while
loops, do-while
loops, and Swift’s powerful switch
statement. You may have noticed that arrays weren’t covered in part one. We’ll make up for that here and also focus on Swift’s other collection type: dictionaries. Finally we’ll round off part two by covering enumerations.
ECMAScript developers following this series will discover that most of what is covered here isn’t that dissimilar to the features found in languages such as JavaScript and ActionScript. Enumerations being really the only exception for some of you. For those from a C programming background, everything will feel familiar, although you may be surprised at the additional power and flexibility that Swift brings to many of these features.
As stated previously, everything covered in this series of tutorials can also be found in Apple’s own official guide to the Swift programming language. The intention here however is to focus on the elements of the language that are required to get newcomers up and running as quickly as possible. If you have the time and want the full detail then I highly recommend you head straight over to Apple’s Swift Programming Language Guide instead.
Getting Started
If you haven’t worked your way through the first tutorial in the series then I recommend you start from there.
You should also consider installing Xcode 6 and creating a playground to try out his tutorial’s various code examples. Detail regarding that can be found in the first tutorial.
More on Strings
We briefly looked at strings in the first tutorial. Let’s revisit them and get some more detail.
The String
type represents a collection of ordered values of type Character
. Swift’s String
and Character
types are fully Unicode-compliant. As discussed previously, a string literal can be used to initialise your variables and constants:
It’s also possible to create a string that is initially empty:
You can also check whether a string is empty:
playerName = "anonymous"
}
The “equal to” operator (==
) is used to determine if two strings are equal:
let person2 = "Christopher"
if person1 == person2 {
println("Both people share the same name.")
}
The addition (+
) operator can be used to concatenate strings:
var surname = "Skywalker"
var name = forename + " " + surname
Only string variables can be changed after they are initialised. Once a string constant has been set, it cannot be altered. The following example will result in a compile-time error:
name = "Darth Vader"
Characters
As stated, a string is an ordered collection of characters. You can access each of a string’s characters with a for-in
loop. Here’s an example:
for c in sith {
println(c)
}
This will result in the following being output:
a
r
t
h
println()
call. You should see the text (5 times)
and an icon of a dot to the right of that.
If you click that icon, the timeline assistant pane will open and you’ll be able to see the result from each iteration of your loop.
In the code example above, the c
variable will hold a single character at any one time and is therefore of type Character
.
As with strings, the “equal to” operator (==
) is used to check if two characters are equal:
let character2: Character = "c"
if character1 == character2 {
println("Both characters are the same.")
}
Notice that the Character
type had to be explicitly declared to prevent both variables from being inferred as String
types. There is no single-quote syntax for character literals in Swift.
It’s not possible to check the equality of a String
against a Character
without first converting the character to a String
type. Here’s an example:
let myString = "c"
if String(myCharacter) == myString {
println("Both characters are the same.")
}
You can append a Character
value to a String
with the append()
method. Here’s an example:
let exclamationMark: Character = "!"
greeting.append(exclamationMark)
You can obtain the number of characters in a string by using the global count()
function:
var numberOfCharacters = countElements(jedi)
println(numberOfCharacters)
The above example will output 14
.
fullname
. Finally check the number of characters stored within your fullname
variable. If it’s over 15 characters in length then print The name is too long.
to the appropriate output. Otherwise, simply print your full name.String Interpolation
We’ve already utilised string interpolation when working with the global println()
function. String interpolation allows you to insert variables, constants, literals, and expressions as placeholders directly within a string. This is done by wrapping each item in parentheses and escaping them with a backslash before the opening parenthesis. Here’s an example:
var kills = 64
let pointsPerKill = 10
let message = "\(name) scored a total of \(kills * pointsPerKill) points"
This will result in a message
variable that contains the string value: Luke Skywalker scored a total of 640 points
.
Character Indexing
The internal Unicode representation of strings in Swift means that random access of a string’s individual Character
values via integer indexing is not supported. For example, you may reasonably expect the following to work:
let lastCharacter = pilot[4]
Instead you need to query a string for its starting index and then use the global advance()
function to move to the desired position within the string. Here’s the previous example rewritten:
let index = advance(pilot.startIndex, 4)
let lastCharacter = pilot[index]
This will result in the lastCharacter
constant being assigned a value of e
. It’s important to note that the index
constant above is not of type Int
. Instead it’s a String.Index
opaque type, which Swift’s character and range indices are based on.
Christopher Caleb
would be displayed as Christopher Cal...
.Arrays
Arrays are one of two collection types supported by Swift (Dictionaries being the other). Each element within a Swift array must be of the same type.
Initialising Arrays
An array can be declared and initialised with an array literal. Here’s an example:
This creates an array that initially contains two strings: "c3p0" and "r2d2". Of course, thanks to Swift’s type inference we can actually shorten the above example to:
An immutable array can be created by using a constant instead of a variable:
In the example above, the array cannot be altered after it’s initialised. By assigning your array to a variable instead, you’ll be free to add, remove, or change values stored within it.
You can create an empty array of a specified type with the following:
Or alternatively by using Swift’s initializer syntax:
There’s also an initializer for creating an array of a certain size and populating it with a provided default value. The following creates an array of 100 integers, with each initialised to 64:
Accessing and Modifying an Array
Swift uses subscript syntax and zero-based indexing to obtain and modify the value of items within an array. Here’s an example that changes an array’s 5th item from 1500
to 2000
:
scores[4] = 2000
The following example obtains the value of the first item within the array:
var lowestScore = scores[0]
Subscript syntax can even be used to replace a range of values within an array:
topFriends[0...2] = ["Christopher", "Alan", "Freddy"]
This will replace the first three strings within the topFriends
array with “Christopher”, “Alan”, and “Freddy”.
You can add a new item to the end of an array with the append()
method:
droids.append("r5d5")
println(droids)
The code example above will output [c3p0, r2d2, r5d5]
.
It’s also possible to append an array of compatible values to an existing array. This is done with the addition assignment operator (+=
):
droids += ["r5d5", "ig88", "tc14"]
println(droids)
The example above will print [c3p0, r2d2, r5d5, ig88, tc14]
to the appropriate output.
Swift provides an insert(atIndex:)
method, which inserts an item at the specified index:
bestScores.insert(150, atIndex:3)
println(bestScores)
This will insert a value of 150
immediately after 100
in the array. The final output will be: [10, 50, 100, 150, 500]
.
You can remove an item at a specific index with the removeAtIndex()
method:
bestScores.removeAtIndex(1)
println(bestScores)
This will remove the second item from the array and print the following: [10, 100, 500]
.
You can obtain the number of items in an array via its count
property:
let numberOfJedi = jedi.count
Accessing Outside An Array’s Bounds
A runtime error is triggered if you attempt to obtain or set a value for an index that is outside an array’s bounds. For example:
let name = jedi[64]
println("Name: \(name)")
This will result in a runtime error since we’re trying to access the 65th string within an array that only contains four values.
Before accessing or modifying a value within an array you should use its count
property to determine whether the index position you are using is valid:
var index = 64
if index < jedi.count {
let name = jedi[index]
println("Name: \(name)")
}
The example above avoids the risk of a runtime error. It’s also worth remembering that array indexes are zero-based in Swift. You should take that into account when using an array’s size to determine if an index position is within bounds.
Iterating Over an Array
You can use a for-in
loop to iterate over an array:
for name in jedi {
println(name)
}
The code snippet above will print the following to the appropriate output:
Kenobi
Yoda
Windu
You can also take advantage of Swift’s global enumerate()
function to extract the value and index position of each item into a tuple. Here’s how:
for (index, name) in enumerate(jedi) {
println("\(index): \(name)")
}
This will result in the following being output:
1: Kenobi
2: Yoda
3: Windu
Dictionaries
Unlike arrays, dictionaries do not store items in a specified order. Instead, each item added to a dictionary is associated with a unique key, which acts as an identifier for that item. All items added to a dictionary must be of the same type. The same is true for the unique keys you use also.
Let’s look at a simple example:
We have a dictionary of player scores. Each player’s name is used as a key, and there is a score associated with each key. The keys are of type String
and the values are all of type Int
. In other words, we have declared a dictionary that has a type of [String: Int]
.
Since we initialised our scores
dictionary with a literal we can let Swift infer the dictionary’s type for us. So we can shorten our original example to this:
An immutable dictionary can be created by using a constant instead of a variable:
You can create an empty dictionary of a specified type with the following:
Or alternatively by using Swift’s initializer syntax:
Accessing and Modifying a Dictionary
Subscript syntax is used to access or modify an existing value within a dictionary. Here’s an example of a value being modified:
scores["Freddy"] = 20000
A little more effort is required to access a value. It’s possible that the key you use with your subscript may not actually have an associated value within the dictionary:
let score = scores["Bob"]
As you can see from the example above, the key Bob
doesn’t actually exist within the dictionary. When this is the case, nil
will be returned. If you think back to the first tutorial in the series, you’ll remember that variables and constants in Swift cannot be nil
and must always have a value associated with them. To get around this constraint, Swift provides optionals, which can either have a value or no value at all (nil
).
That means that in the example we just looked at, the dictionary’s subscript is actually returning an optional rather than the value that’s directly associated with the key. Once you’ve determined that the optional retrieved from the dictionary isn’t nil
, you’ll need to unwrap it (place an exclamation mark at the end of the optional’s name) to retrieve its value. Here’s a concrete example:
let score = scores["Bob"]
if score != nil {
println("Bob’s score is: \(score!)")
} else {
println("There is no score for Bob")
}
As an alternative to using an if
statement before obtaining an optional’s value, you can also use optional binding. Here’s the above example re-written:
if let score = scores["Bob"] {
println("Bob’s score is: \(score)")
} else {
println("There is no score for Bob")
}
Kenobi 120
Maul 80
Vader 90
Yoda 1000
Windu 110
Emperor 200
Given the following array of names ["Maul", "Vader", "Emperor"]
, write a program that finds each character’s rating and prints it to the screen along with their name.
Subscript syntax can also be used to add new items to a dictionary:
scores["Christopher"] = 50000
The code snippet above adds a new key named Christopher
and associates a value of 50000
with it.
You can obtain the number of items in a dictionary via its count
property:
let numberOfScores = scores.count
Iterating Over a Dictionary
You can use a for-in
loop to iterate over a dictionary:
for (name, score) in scores {
println("\(name): \(score)")
}
In the above example, each item in the dictionary is returned as a (key, value)
tuple. The tuple’s members are decomposed into constants called name
and score
, then printed to the appropriate output as:
Alan: 8000
Freddy: 1000
It’s possible to retrieve a collection of keys or values from a dictionary via its keys
and values
properties. You can then iterate over your collection using a for-in
loop. Here’s an example that iterates over the keys from our scores
array:
println("Name: \(name)")
}
You can also initialise a new array with either your collection of keys or collection of values. Here’s an example:
Note from the example above that the your array’s type needs to match the type of the values stored within your dictionary.
It’s important to remember that items within a dictionary have no specific order. In other words, you can’t be guaranteed that keys, values, or key-value pairs will be retrieved in any specific order when attempting to iterate over a dictionary.
Alan 8000
Amanda 2500
Elizabeth 120
Freddy 11050
Helen 60
Cheryl 30
Write a program that iterates over your dictionary and displays the names of those who have scored over 5000 points. Also display each person’s score alongside their name.
While Loops
Swift provides the familiar while
and do-while
loops. Let’s take a look at the while
loop.
While Loop
The general structure of a while
loop isn’t difficult to grasp. Here’s an example:
while index < 5 {
println("index: \(index)")
index++
}
As with the for
loop (from part one), parentheses aren’t required in Swift. The code above will result in the following output:
index: 1
index: 2
index: 3
index: 4
The while
loop starts by evaluating its condition. If the condition is true
, the loop’s block of statements is repeated until the condition becomes false
. In the case of our example, the loop continues until the index
variable no longer has a value less than 5
.
Do-While Loop
The do-while
loop is a variation of the while
loop. It performs a single pass of the loop’s block of statements before evaluating the loop’s condition. Here’s the previous example rewritten to use a do-while
loop:
do {
println("index: \(index)")
index++
} while index < 5
The major difference between both variations is that the do-while
loop will always execute the statements within its block at least once, whereas a while
loop’s block may not execute at all if its condition initially evaluates to false
.
Don’t forget about block scope. Variables and constants declared within while
and do-while
loops are only valid within the scope of each loop.
Switch Statement
Swift’s switch
statement is extremely powerful. At a glance it may not look that different from the switch
statement provided by other languages. Take this simple example as a starting point:
switch name {
case "Skywalker":
println("\(name) is a Jedi")
break
case "Kenobi":
println("\(name) is a Jedi")
break
case "Vader":
println("\(name) is a Sith")
break
case "Dooku":
println("\(name) is a Sith")
break
default:
println("I don’t know if \(name) is a Jedi or Sith")
}
Running this within your playground will result in Dooku is a Sith
being displayed in the sidebar. More or less as you’d expect, right?
switch
statement had all the hangups of the C programming language. Our current example uses a break
statement at the end of each case. However this isn’t required since switch
statements in Swift do not automatically fall through to the next case. In other words, we can (and should) rewrite our example with the break
statements removed:
switch name {
case "Skywalker":
println("\(name) is a Jedi")
case "Kenobi":
println("\(name) is a Jedi")
case "Vader":
println("\(name) is a Sith")
case "Dooku":
println("\(name) is a Sith")
default:
println("I don’t know if \(name) is a Jedi or Sith")
}
It should also be noted that switch
statements in Swift should be exhaustive. What I mean by that is, there should be a matching case statement for every possible value. Where that isn’t feasible, the default
keyword should be used to provide a catch-all.
default
statement at the end of our current example. You’ll receive the following error within your playground:
Switch must be exhaustive, consider adding a default clause
Before continuing, add the default
case back into your code example.
Looking at our example again, you should notice that the first and second cases produce the same result. The same is also true of the third and fourth cases. You may be tempted to re-factor your switch
statement like this:
switch name {
case "Skywalker":
case "Kenobi":
println("\(name) is a Jedi")
case "Vader":
case "Dooku":
println("\(name) is a Sith")
default:
println("I don’t know if \(name) is a Jedi or Sith")
}
This code will fail to compile for two reasons. First, as discussed, Swift’s Switch
statement does not fall through to the next case by default. Secondly, in Swift, the body of each case must contain at least one executable statement.
To get around this problem, Swift lets you write a comma separated list of matches for a single case. Here’s how the previous code example should be written:
switch name {
case "Skywalker", "Kenobi":
println("\(name) is a Jedi")
case "Vader", "Dooku":
println("\(name) is a Sith")
default:
println("I don’t know if \(name) is a Jedi or Sith")
}
We currently print a message if a match is not found for the value of the name
variable. What if, by design, nothing was to be printed when there was no match? While the use of the break
statement is discouraged, it actually comes in handy for situations such as this:
switch name {
case "Skywalker", "Kenobi":
println("\(name) is a Jedi")
case "Vader", "Dooku":
println("\(name) is a Sith")
default:
break
}
Explicit Fallthrough
As has just been discussed, switch
statements in Swift do not automatically fall through the bottom of each case and into the next one. Therefore there’s no need to explicitly place a break
statement at the end of each case since the execution of your switch
statement will terminate as soon as the first matching case is completed.
But what if you actually had a need to drop through to the next case? Swift allows you to do that so long as you’re explicit about it. This prevents the common programming errors you see in other languages where execution dropped through to the switch
statement’s next case by accident. The fallthrough
statement is used for such situations. Here’s our previous example re-written to use it:
switch name {
case "Skywalker":
fallthrough
case "Kenobi":
println("\(name) is a Jedi")
case "Vader"
fallthrough
case "Dooku":
println("\(name) is a Sith")
default:
break
}
While the code snippet does technically work, it has been contrived in order to illustrate how the fallthrough
statement works. If you find yourself writing code like this then you really should consider ditching the fallthrough
statement and created comma separated lists of matches for each case instead.
Range Matching
This is where things get interesting. Swift allows the value in a switch
statement to be checked against a range. Here’s our if-else
code example from part one, but this time using a switch
statement:
switch energy {
case 0:
println("Vader’s lightsaber cuts through you.")
case 1...20:
println("Your powers are weak old man.")
case 21...40:
println("You have much to learn.")
default:
println("The force is strong with you.")
}
The example above would result in You have much to learn.
being printed to the appropriate output.
We only see the use of the closed range operator (a...b)
here, but the half-open range operator (a..<b)
can obviously be used too.
Tuples
Tuples can also be matched in a switch
statement, giving you greater pattern matching capabilities. Here’s a simple example that recognises types of iOS devices:
switch currentScreen {
case (768, 1024):
println("A non-Retina iPad")
case (1536, 2048):
println("A Retina iPad")
case (320, 480):
println("A non-Retina iPhone")
case (640, 960), (640, 1136), (750, 1334), (1080, 1920):
println("A Retina iPhone")
default:
println("Unknown iDevice")
}
This would print A Retina iPhone
to the appropriate output.
As discussed in part one, you can use an underscore to ignore values within a tuple that you aren’t interested in. In addition, it’s also possible to use the two range operators when specifying matching tuples:
switch player {
case (0, _):
println("Game Over!")
case (1..<10, _):
println("Energy Low!")
case (_, 5...10):
println("Keep up the good progress")
case (_, 11...25):
println("Awesome! Keep going!")
default:
println("Doing fine")
}
In the above code example, a player’s status is printed based on their current energy and the game level they have reached. The player’s health is regarding as being of greater importance, so a message related to their energy will take priority.
This is handled by the first two case statements, with an underscore used to ignore the player’s current level. The next two are more concerned with the player’s level progress, with an underscore being employed to ignore the player’s energy value. Also notice the use of the closed range and half-open range operators throughout the switch
statement’s cases.
Running the above code within your playground would result in Awesome! Keep going!
being displayed in the sidebar.
With these relatively simply examples, we’re seeing more complex pattern matching capabilities available with Swift’s switch
statement compared to languages such as Objective-C or more high-level languages such as JavaScript.
Value Binding
The values a switch
case matches can be bound to temporary constants or variables. These constants and variables can then be used within the case’s body. Here’s an example:
switch player {
case (0, let level):
println("Game Over! You reached level \(level).")
case (let energy, 100):
println("You completed the game with a health of \(energy).")
case let (energy, level):
println("You are on level \(level) with a health of \(energy).")
}
This would result in You completed the game with a health of 15.
being output to your playground’s sidebar.
Where
Finally, a where
clause can be used in a switch
statement’s case to check for additional conditions. Here’s the previous example with a few more conditions added:
switch player {
case (0, let level):
println("Game Over! You reached level \(level).")
case (let energy, 100):
println("You completed the game with a health of \(energy).")
println("You are being swamped by the enemy! Do something!")
case let (energy, level):
println("You are on level \(level) with a health of \(energy).")
}
The above example would result in You are being swamped by the enemy and are close to death.
being sent to the appropriate output.
Notice that our code example introduces a constant named enemyCount
, which appears in both usages of the where
clause. The first where
clause also uses a temporary energy
constant that is bound to the first tuple value matched by its associated case.
Write a program that takes an (x, y) point and provides feedback as to where that point is. If the point is at the origin then print Is at the origin
to the appropriate output. If the point is within the square then print Within the square
. If the point is within the rectangle then print Within the rectangle
. If the point is lying somewhere along the x-axis then print On the x-axis
. If the point is lying somewhere on the y-axis then print On the y-axis
. For any other position, then display Somewhere else
.
Use a tuple to define the point and take advantage of Swift’s switch
statement to determine the point’s position. Test you code with a few locations such as (0, 0)
, (1, 1)
, (3, 6)
, (0, 20)
, (20, 0)
, and (40, 70)
.
I hope you can see from these examples just how powerful Swift’s switch
statement can be.
Enums
If you’re from a JavaScript or ActionScript background then you may not be familiar with enumerations. If, on the other hand, you’re familiar with Objective-C or other similar languages then you’ll be pleasantly surprised by the flexibility of enumerations in Swift.
So what is an enumeration? Put simply, an enumeration is a type that represents a group of related values. For example, you may want to create a type that represents the days of the week, or a type that represents the months in a year. Another example could be a type that represents the four points of a compass.
Let’s use the days of the week as a concrete example:
case Monday
case Tuesday
case Wednesday
case Thursday
case Friday
case Saturday
case Sunday
}
In the example above we have defined an enumeration type named Day
that contains the days of the week (Monday
, Tuesday
, Wednesday
, Thursday
, Friday
, Saturday
, and Sunday
) as its members.
The case
keyword was used to declare each member of the enumeration. It’s also possible to comma separate our members on a single line.
Here’s an alternative way of declaring our enumeration:
case Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}
Now that our Day
enumeration type has been created, lets see how to use it:
We’ve just created a variable named today
that is set to the member Saturday
from our enumeration. The today
variable’s type has been inferred by the fact that it has been initialised with one of the values from Day
. Once the variable has been initialised, you can use a shorthand syntax to set it to a different value belonging to the enumeration:
Of course, the following is also valid, but the shorthand syntax used above is preferred:
Conditional Statements
As you might expect, an enumeration can be used with if
statements and switch
statements. Let’s start with a simple example that makes use of the if
statement:
if today == .Wednesday {
println("Swimming lessons today")
}
The code snippet above will print Swimming lessons today
to the appropriate output. Once again, notice the use of the shorthand syntax (.Wednesday
rather than Day.Wednesay
) within the if
statement’s condition.
Now let’s take a look at a more sophisticated example that takes advantage of the switch
statement:
switch today {
case .Monday, .Tuesday, .Wednesday, .Thursday, .Friday:
println("Work today")
case .Saturday, .Sunday:
println("It’s the weekend!")
}
Adding the following to your playground file would result in It's the weekend!
being displayed within the sidebar.
It’s also worth noting that the default
statement wasn’t used in our switch
statement. There was no need to because an exhaustive list of all possible enumeration values was provided.
Write a small program that plays out a single game of Rock-paper-scissors.
Declare an enumeration named Shape
that contains the game’s three shapes: rock, paper, and scissors.
Declare two constants named player1
and player2
to hold each player’s chosen shape.
Finally, use an if
statement to handle the logic to determine which player has won. You’ll also need to handle a tie situation. If player one wins then Player 1 wins
should be displayed. If player two wins then display Player 2 wins
. In the event of a tie situation, The game is tied
should be output.
Test your code by setting different values for your player1
and player2
constants.
Raw Values
In programming languages such as Objective-C, each of an enumeration’s members is assigned an integer value, typically starting from 0 and being incremented for each subsequent member. In Swift, each member is a value in its own right and does not require an integer to be assigned to it. However, you can assign an integer (or any other type) to each member if you so require. These values are known as raw values and must all be of the same type.
Let’s take a look at an example where we use an integer to stipulate an order for our days of the week:
case Monday
Saturday
}
Notice that we assign a value of 1
to our first member, then increment that value by one for each subsequent member. Doing so isn’t a requirement. We can assign any arbitrary value to our members. However, if we do wish to apply an incremental sequence of integers to each of our members then we only need to assign a default value to the first member and the remaining values will be inferred:
case Monday
}
You can obtain a member’s raw value with its rawValue
property:
println("Today’s position within the week is: \(position)")
This would result in Today's position within the week is: 3
being sent to the appropriate output.
It’s also possible to find an enumeration’s member based on a raw value. Your enumeration will automatically have an initializer that you can take advantage of. Here’s an example:
if let day = Day(rawValue: positionToFind) {
if day == .Wednesday {
println("Swimming lessons today")
} else {
println("Not up to anything today")
}
}
The initializer returns either an enumeration member or nil
if a member doesn’t exist for the specified raw value. In other words, it returns an optional enumeration member. Since we are dealing with an optional in our example above, optional binding is used to ensure that we aren’t inadvertently working with a variable whose value is nil
.
The example above will result in Swimming lessons today
being printed to the appropriate output.
Associated Values
We’ve just seen how the members of an enumeration can be pre-populated with raw values. As an alternative you can also associate a value with an enumeration’s member. The distinction between the two is that a raw value is fixed to a specific member, whereas an associated value can vary every time you use that member.
As an example, let’s consider an enumeration that’s used to represent the status of a construction project. The construction can be either on time, or delayed. Here’s how that may be represented:
case OnTime
case Delayed
}
With this we can easily create a variable that specifies that a construction project is delayed:
However, we can actually declare a better enumeration that can store information detailing how many months a construction is actually delayed by. Here’s an improved version of our enumeration:
case OnTime
case Delayed
}
The Delayed
member now has an integer value associated with it, and that value can be used to store how long (for example, in months) the project has been delayed for. Let’s take a look at how to use it:
The line above states that construction is six months behind.
If at any point, there are further delays then the variable can be updated:
We can use a switch
statement to check for either of the enumeration’s members, and also match against any associated values that may belong to them. Here’s a complete example using our ConstructionStatus
enumeration type:
case OnTime
case Delayed(Int)
}
case .OnTime:
println("The Death Star is complete. The Emperor is pleased.")
case .Delayed
println("Construction is slightly behind schedule.")
case .Delayed
println("Construction is behind schedule.")
default:
println("The Emperor is most displeased.")
}
Not only are we seeing the flexibility of enumerations within Swift, we’re also once again seeing just how powerful Swift’s switch
statement is. In our code above, we can see the closed range operator being used to specify a case where construction is between 0 and 3 months behind, and another case where construction has been delayed between 4 and 6 months.
It’s also possible to extract the value associated with an enumeration’s member. Here’s the above example re-written to display the actual number of months the project is delayed by if it is already seven months late or more:
case OnTime
case Delayed(Int)
}
case .OnTime:
println("The Death Star is complete. The Emperor is pleased.")
case .Delayed(0...3):
println("Construction is slightly behind schedule.")
case .Delayed(4...6):
println("Construction is behind schedule.")
println("Construction is \(months) months behind. " +
"The Emperor is most displeased.")
}
I hope you can see the benefit of using Swift’s enumerations. While we’ve spent significant time with enumerations, there’s actually still a lot more to learn. For example, enumerations support many of the features that are traditionally only associated with classes including instance and static methods, but we’ll leave that for another day.
Next Time
Once again we’ve covered a significant amount of ground. There’s plenty to digest so please spend as much time as possible experimenting within a playground until you’re confident you fully understand everything. That goes for many of the language features (optionals, tuples, range operators, etc) from part one that were utilised in this second tutorial.
In part three we’ll start by looking at functions before moving on to structures. Structures share many of the same features as classes, and are therefore a good place to start before exploring Swift’s object-oriented features.
I’d like to reiterate the message from last time. There really isn’t anything particularly difficult about the basics of Swift. Coming from other languages, some of Swift’s concepts may seem unfamiliar, but spend some time working with them and you’ll quickly be able to master them.
See you in part three.