Getting Started with Swift 3

35 minutes, 9 seconds

Swift 3 is said as the last major changes in the core language. What it means that the code is promised to compilable on the next version of Swift. So having the core right is really important to fulfil this ambition.

Swift is meant to be an open source project. So if you ever learn about Swift, the knowledge will not limited yourself to develop for Apple platform only. It’s possible to use Swift on various kind of usage once it’s being adapted widely by another platforms.

On WWDC 2016 (Session 404) there is a talk about getting started with Swift 3, let’s relearn everthing we know about Swift so far.

Constants

General principle in Swift, if something doesn’t need to change, we declare it as a constant.

We indicate constant with let following with the name, and the type with a colon (:) in the middle. On the right side after the equal (=) is the value for the constant.


let language: String = "Swift"
let introduced: Int  = 2014
let isAwesome: Bool  = true

Notice the way we naming the name with lowerCamelCase and the type with UpperCamelCase.

Type Inference

Now, if we look at the things on the right here, it’s pretty obvious, actually, that what I want is a string, an integer and a Bool, and where this is the case Swift can infer the type for us.

We don’t actually need to write it ourselves. So you still get things that are explicitly typed, but you don’t have to write as much code.


let language   = "Swift" // inferred as String
let introduced = 2014 // inferred as Int
let isAwesome  = true // inferred as Bool

Variables

Things do sometimes need to change. So here’s a variable indicated with var, and it’s for the version of the language.


var version = 1
version = 3

Buildings Strings

So a common thing to want to do in programming is to build strings from other values. We could do this by concatenating strings together, as shown here.


let conference = "WWDC"
let message = "Hello, " + conference + "!"
// "Hello, WWDC!"

String Interpolation

Swift has a neater way to do concatenating, known as string interpolation, and this is how it looks.


let conference = "WWDC"
let year = 2016
let message = "Hello, \(conference) \(year)!"
// "Hello, WWDC 2016!"

We can add other values as well, such as integers here putting the year in. And we could even add expressions as well. We can add year + 1 for some code that would work for a future year.

We can put strings and other values inside a larger string by wrapping them in \(<#var#>).

We’re not just limited to strings, however. We can add other values as well, such as integers here putting the year in. And we could even add expressions as well. We can add year + 1 for some code that would work for a future year.


let message = "Hello, \(conference) \(year+1)!"
// "Hello, WWDC 2017!"

Unicode

Now, strings in Swift are fully Unicode friendly. They’re just as happy with ASCII as they are with dog, cows or with flags. And the same also goes for any constants and variables you create.


let instruction = "Beware of the ??" 
let internationalHarmony = "#$?"
let π = 3.1415927
let 鼠 = "?"

Characters

Every string has a property called characters. It gives us a collection of the characters in the string and we can access the count property of that collection to see how many there are.


let dogString = "Dog⁈?"
print("\(dogString) is \(dogString.characters.count) characters long")
// Dog⁈? is 5 characters long.

Let’s iterate over each of those characters in turn, using the for-in loop and print each one of them on its own line, and you can see we do, indeed, have five characters; D, O, G, ⁈ and dog face. Now, in addition to all of these fundamental types we also have some built-in collections.


let dogString = "Dog⁈?"
for character in dogString.characters {
  print(character)
}

// result
D
o
g
⁈
?

Array

And the easiest way to create an array or a dictionary is with a literal. This is an array literal written with square bracketry on the outside and commas between each value.


let names = ["Hijazi", "Nadya", "Qaisara"]

Now, you might notice from the things in this array that they’re all the same type; they’re all strings. It wouldn’t make sense to insert something else in a names array, to have an integer or a Boolean or a bicycle. That would be just weird.

For names we always want them to be strings, and in Swift we can express this. We can say we want an array of strings, so we know as soon as we get anything out of it, we can do string like things with it.

So this is how we write that. This is how we write an array of strings, a string with square brackets around it.


let names: [String] = ["Hijazi", "Nadya", "Qaisara"]

But as we saw earlier on, when it’s clear from the right hand side what kind of type we want, Swift works it out for us, and that happens here as well. We actually don’t need to write the type. It’s clear we want an array of strings.


let names = ["Hijazi", "Nadya", "Qaisara"]
// an array of String values

Dictionary

You might know dictionary as a hash or map table from other languages. Dictionaries look very similar to array.

Their keys and values are separated with a colon. Here we have a dictionary whose keys are strings, the names, and whose values are integers.


let ages = ["Hijazi": 29, "Nadya": 26, "Qaisara": 1]
// a dictionary with String keys and Int values

The same goes for our dictionary. Here it’s clear we want string keys and integer values, so Swift can infer that for us as well, but everything is still clearly typed.

Loops

Swift has all of the loops you might know from other languages.

While Loop

We have a while loop that checks its condition before first executing its body.


while !endOfFile {
   readLine()
}

Repeat-While Loop

And a repeat-while loop, which executes its body once before checking a condition to see if it should continue.


repeat {
   performTask()
} while tasksRemaining > 0

For-In Loop (Characters)

And as we saw earlier, we have the for in loop, which we used to iterate over the characters of a string.


let dogString = "Dog⁈?"
for character in dogString.characters {
  print(character)
}

// Result
D
o
g
⁈
?

For-In Loop (Closed Ranges)

But that’s not the only thing the for in can be used with. We can use it to iterate over a range. Here we have a range that runs through from 1 through 5 and includes most of those numbers, which we’re using to print five entries from the four times table. We write this as 1…5.


for number in 1...5 {
   print("\(number) times 4 is \(number * 4)")
}

// Result
1 times 4 is 4
2 times 4 is 8
3 times 4 is 12
4 times 4 is 16
5 times 4 is 20

That is called a closed range because it includes both of those numbers.

For-In Loop (Half-closed Ranges)

However, sometimes it’s useful to have a range that runs up to one less than its final number. Here’s an example of where that’s useful. I have an array of integers, but I only want to print the first five. Now, because array indices start from 0, I actually want indices 0 through 4.


let results = [7, 52, 9, 33, 6, 12, 86, 4, 22, 18, 3]
let maxResultCount = 5
for index in 0..<maxResultCount {
   print("Result \(index) is \(results[index])")
}

// Result
Result 0 is 7
Result 1 is 52
Result 2 is 9
Result 3 is 33
Result 4 is 6

So for that we can use the half-closed range operator, ..< because it runs the one less than the final number, in this case 5.

For-In Loop (Arrays)

We can use a for-in loop with an array. Here we’re printing a message for each of the names in our array.


for name in ["Lily", "Santiago", "Justyn", "Aadya"] {
   print("Hello, \(name)!")
}

// Result
Hello, Lily!
Hello, Santiago!
Hello, Justyn!
Hello, Aadya!

For-In Loop

And we can also use it with a dictionary. Now, note here that we’re iterating over the key and the value, the name and the age, at the same time.


let ages = ["Mohsen": 17, "Amy": 40, "Graham": 5]
for (name, age) in ages {
   print("\(name) is \(age) years old")
}

// Result
Mohsen is 17 years old
Amy is 40 years old
Graham is 5 years old

And this is an example of Swift speech known as a tuple, which lets you combine those multiple values together and use them at the same time.

Modifying Array & Dictionary

Modifying Array

So how would we modify these collections? Well, here’s my packing list for WWDC this year. I’ve declared it as a variable so I can change it, but I’ve included the essentials, socks and shoes. Now, at WWDC 2014 I forgot to pack my socks and it was a nightmare, so I’m not making that mistake again.

So let’s check that the first item in this array is definitely socks. After 2014, if I put it on the list, it will be first.

We do this using a subscript, writing an index inside square brackets after the array name, and if we print this value, I have indeed remembered to add socks. Socks and shoes will not be enough, however, for a week of the conference.


var packingList = ["Socks", "Shoes"]
print(packingList[0])

// Result
"Socks"

I’ll need more things. So let’s append a new item. Let’s append some trousers to this array as well, which we do using the append method.


var packingList = ["Socks", "Shoes"]
packingList.append("Throusers")

// Result
["Socks", "Shoes", "Trousers"]

But there’s a problem here. The conference is in America and they don’t call them trousers, they call them pants, and that’s going to cause all kinds of confusion. So let’s change a value in our array.

Let’s change this to be jeans instead. Again, we use a subscript to do so, to change the item in index two.


var packingList = ["Socks", "Shoes"]
packingList.append("Throusers")
packingList[2] = "Jeans"

// Result
["Socks", "Shoes", "Jeans"]

Jeans are called the same thing everywhere, so this shouldn’t cause confusion. Now, the conference is in California where it is always hot and sunny, so let’s add a few more items. Let’s add some shorts, some sandals and some sunblock.

We can do this using the append contents of method and pass in a compatible array, another array of strings here, and they all get appended at the same time.


var packingList = ["Socks", "Shoes"]
print(packingList[0])
packingList.append("Trousers")
packingList[2] = "Jeans"
packingList.append(contentsOf: ["Shorts", "Sandals", "Sunblock"])

// Result
["Socks", "Shoes", "Jeans", "Shorts", "Sandals", "Sunblock"]

That said, whilst the conference is in California, it’s in San Francisco, where it is not always hot and sunny. So maybe let’s change those three items and replace them with a hoodie and a scarf instead. We can do this by passing a range into the subscript. And note that we’re changing three items with two, this is still perfectly valid in Swift.


var packingList = ["Socks", "Shoes"]
print(packingList[0])
packingList.append("Trousers")
packingList[2] = "Jeans"
packingList.append(contentsOf: ["Shorts", "Sandals", "Sunblock"])
packingList[3...5] = ["Hoodie", "Scarf"]

// Result
["Socks", "Shoes", "Jeans", "Hoodie", "Scarf"]

Modifying a Dictionary

So what about a dictionary? Let’s modify a dictionary.

Well, here I have my ages dictionary from before.


var ages = ["Mohsen": 17, "Amy": 40, "Graham": 5]

// Result
["Mohsen": 17, "Amy": 40, "Graham": 5]

I’d like to add somebody else to it, and I do this just by adding a value for a key that’s not already there using a subscript. Here I’ve added Justyn.


var ages = ["Mohsen": 17, "Amy": 40, "Graham": 5]
ages["Justyn"] = 67     // Adds a new value for "Justyn"

// Result
["Mohsen": 17, "Amy": 40, "Graham": 5, "Justyn": 67]

But thinking about it, it was Justyn’s birthday last week so this value is now incorrect. I need to update it, which I do in exactly the same way. I just assign a different value for the same key and now my dictionary’s correct.


var ages = ["Mohsen": 17, "Amy": 40, "Graham": 5]
ages["Justyn"] = 67     // Adds a new value for "Justyn"
ages["Justyn"] = 68     // Changes the value for "Justyn"

// Result
["Mohsen": 17, "Amy": 40, "Graham": 5, "Justyn": 68]

Optionals

Retrieving Value From Dictionary

What if I want to retrieve a value from the dictionary?


let ages = ["Mohsen": 17, "Amy": 40, "Graham": 5]
// Devon?
// Daryl?
// Daniel?

What if I want to see if we have an age for Devon or for Daryl, or perhaps for Daniel? Well, there might be a value in the dictionary for these people, but there might not, and we need a way to model that, and this is a great use case for a Swift feature known as Optionals.

Optionals

If we tried this for Amy, we might expect a value of 40 perhaps.


let ages = ["Mohsen": 17, "Amy": 40, "Graham": 5]
let possibleAge: Int = ages["Amy"]

// Note
A value of 40, perhaps?

But if we tried it for Daryl, what should we get then? There’s no value here for Daryl.


let ages = ["Mohsen": 17, "Amy": 40, "Graham": 5]
let possibleAge: Int = ages["Daryl"]

// Note
?????

Think of it like this. There either is a value in the dictionary and it’s an Int, that’s for Amy, or there’s no value, there’s no Int, as in the case of Daryl.

So what we have here is an optional Int, which we write as Int?.


let ages = ["Mohsen": 17, "Amy": 40, "Graham": 5]
let possibleAge: Int? = ages["Daryl"]

Checking for an Optional Value

And the question mark means there might be a value here, but there might not. Now, we can check to see if we found a value by comparing it against nil. Nil is just a special way, a shorthand way of writing no value.

If we try this for Daryl, there is no value, we’d print the message. Age not found.


let ages = ["Mohsen": 17, "Amy": 40, "Graham": 5]
let possibleAge: Int? = ages["Daryl"]
if possibleAge == nil {
   print("Age not found.")
}

// Result
Age not found.

If we try this for Amy, well, we do find a value so it doesn’t equal nil and so we don’t print the message.

Typically, however, we don’t just want to check for a value. We actually want to use it if it exists, and Swift has a really good shorthand for writing this, which we write as if let.


let ages = ["Mohsen": 17, "Amy": 40, "Graham": 5]
if let age = ages["Amy"] {
   print("An age of \(age) was found.")
}

// Result
An age of 40 was found.

Now, this says here the dictionary contains a value for Amy, let a new constant called age equal that value. And then we can use that value inside the if statement.

And note that we use it as an actual integer. It’s not optional anymore. The if statements checks for the value, unwraps it and gives us back a normal integer that we can do integer like things with.

Flow Control

If Statement

So we’ve seen a few if statements so far. Here’s another that prints a birthday message. There are two things to note about this statement.

Firstly, we don’t need parentheses around the conditions so we can just write them as they are. And secondly, we do add curly braces around each part of the statement to make it explicit which bits of code are going to be run.


let age = 32
if age == 1 {
   print("Happy first birthday!")
} else if age == 40 {
   print("Happy 40th birthday!")
} else {
   print("Happy plain old boring birthday.")
}

// Result
Happy plain old boring birthday.

Switch Statement

In addition to if, we also have a switch statement, and this is useful for writing maybe more complex, more powerful matches. This switches over the current value of a constant or a variable and matches certain cases that can occur.

So, for example, we can have the case here for an age where the value is one and we want to print a simple happy first birthday message.


let age = 32
switch age {
case 1:
   print("Happy first birthday!")
case 13...19:
   print("Happy birthday, teenager!")
case let decade where decade % 10 == 0:
   print("Happy significant \(decade)th birthday!")
default:
   print("Happy plain old boring birthday.")
}

// Result
Happy plain old boring birthday.

We can also match against ranges. Here matching any value that would make someone a teenager. And we can match more complex patterns, such as this one, which says that a temporary constant called decade equal the value that we’re currently matching, check if it will divide cleanly by 10, and if so, use it to print a special birthday message for anyone who’s just turned 30 or 40 or some other significant age.

But there’s a problem with this statement as it stands. What would happen if we wanted to print a message for someone who was 41, or 97 or 56? Well, they wouldn’t get a message, and that seems really unfortunate, especially on their birthday.

Frankly, Swift helps us out here. Swift makes sure that every switch statement is complete, that you don’t accidentally forget one of the cases that you might need. And in this case we can add a default statement which catches every other case we hadn’t already caught above and just says, Happy plain old boring birthday.

Switch Statement II

Here’s another switch statement. This one takes a string value, user name, and a Boolean value that indicates whether that user’s password is valid, and we’ll use both of these values together to work out an appropriate message to display when this user tries to log into a restricted area.


let userName = "admin"
let passwordIsValid = true
switch (userName, passwordIsValid) {
case ("admin", true):
   print("Welcome back, administrator!")
case ("guest", _):
   print("Guests are not allowed in this restricted area.")
case (_, let isValid):
   print(isValid ? "Welcome to the restricted area!" : "ACCESS DENIED.")
}

And to do this we can switch over both values at the same time using a tuple, same as we did earlier on.

So this means we can write some really, really interesting use cases, some really interesting switch cases.

We can have the case where the user name is admin and the password is true, and print a message to welcome back our administrator.

Now, in the case of a guest we never want to allow the guest into the restricted area even if their password is valid, and so we can ignore the password by writing an underscore, and this means just match any possible value here.

For all other users we actually don’t care what the user name is. We just care about the password. So we can ignore the user name again, and instead, we’ve switched on what we want to do with the password’s validity. To do this we create a temporary constant called IsValid, and we then use the ternary conditional operator, that’s the question mark and colon here, to say if it’s valid, use this message; otherwise, use this message. So let’s run that through for a few examples.

If we take our administrator, the password’s valid, they get a special administrator message, as expected. If we try this for a guest, well, even though their password is valid, they get the I’m sorry, you can’t come in message. If we try it for Bob, his password is valid, he gets the welcome message as expected.

But if his password is not valid, he gets access denied. Now, there is one final thing of note about this switch statement, and that’s that it doesn’t have a default condition.

And the reason it doesn’t is it doesn’t need one. It’s already complete.

If we take a look at the final case here, this actually covers all of the possible conditions that we haven’t already matched above and so the switch statement is complete without needing a default. So those are some of the basics of the Swift language.

Functions and Closures

Let’s get started by looking at how you define a function in Swift. You define a function using the func keyword and you implement it inside of the curly braces.

Here we’ve defined a simple function called sendMessage that prints a message to the console. And you call this message in an intuitive way by writing its name, sendMessage, followed by an empty pair of parentheses.


func sendMessage() {
  let message = "Hey there!"
  print(message)
}
sendMessage()

// Result
Hey there!

Function with Parameter


func sendMessage(shouting: Bool) {
   var message = "Hey there!"
   if shouting {
      message = message.uppercased()
   }
   print(message)
}
sendMessage(shouting: true)

// Result
HEY THERE!

Function with Multiple Parameters



func sendMessage(recipient: String, shouting: Bool) {
   var message = "Hey there, \(recipient)!"
   if shouting {
      message = message.uppercased()
   }
   print(message)
}
sendMessage(recipient: "Morgan", shouting: false)

// Result
Hey there, Morgan!

And now when you call the function, you can pass in the recipient’s name. Now, although the message prints as you’d expect, it doesn’t read very well when you call it.


func sendMessage(recipient: String, shouting: Bool) {
   var message = "Hey there, \(recipient)!"
   if shouting {
      message = message.uppercased()
   }
   print(message)
}
sendMessage(to: "Morgan", shouting: true)

// Result
Hey there, Morgan!

Explicit Argument Labels ✅


func sendMessage(to recipient: String, shouting: Bool) {
   var message = "Hey there, \(recipient)!"
   if shouting {
      message = message.uppercased()
   }
   print(message)
}
sendMessage(to: "Morgan", shouting: true)

// Result
Hey there, Morgan!

Argument Labels

For some function the first argument and the function name seems to be redundant.


func sendMessage(message: String, to recipient: String, shouting: Bool) {
   var message = "\(message), \(recipient)!"
   if shouting {
      message = message.uppercased()
   }
   print(message)
}
sendMessage(message: "See you at the Bash", to: "Morgan", shouting: false)

// Result
See you at the Bash, Morgan!

Omitting Argument Labels ✅

Here the argument label actually makes the code harder to read. In case like these, you can write an underscore (_) in front of the parameter’s name.


func sendMessage(_ message: String, to recipient: String, shouting: Bool) {
   var message = "\(message), \(recipient)!"
   if shouting {
      message = message.uppercased()
   }
   print(message)
}
sendMessage("See you at the Bash", to: "Morgan", shouting: false)

// Result
See you at the Bash, Morgan!

Parameter with Default Values


func sendMessage(_ message: String, to recipient: String, shouting: Bool = false) {
   var message = "\(message), \(recipient)!"
   if shouting {
      message = message.uppercased()
   }
   print(message)
}
sendMessage("See you at the Bash", to: "Morgan")

// Result
See you at the Bash, Morgan!

Function Return Values


func firstString(havingPrefix prefix: String,     in strings: [String]) -> String {
   for string in strings {
      if string.hasPrefix(prefix) {
         return string
  } 
}
return "value" // return String 
}

Returning Optional Values

We can change the return type of this function to be an optional String by writing ? after String, and now you can return nil when the String isn’t found.


func firstString(havingPrefix prefix: String,
      in strings: [String]) -> String? {
   for string in strings {
      if string.hasPrefix(prefix) {
         return string
      } 
    }
  return nil 
}

Because the function returns an optional String, we can safely use an if-let statement.


func firstString(havingPrefix prefix: String,
      in strings: [String]) -> String? {
   for string in strings {
      if string.hasPrefix(prefix) {
         return string
      } 
    }
  return nil 
}

var guests = ["Jack", "Kumar", "Anita", "Anna"]
if let guest = firstString(havingPrefix: "A", in: guests) {
   print("See you at the party, \(guest)!")
} else {
   print("Invite must be in the mail.")
}
// Result
See you at the party, Anita!

Struct and Class

All the above code are extremely useful for writing clean, re-usable code. But sometimes you’ll want to create a profile instead of just performing tasks.


struct UserStruct {
    var name: String
    var age: Int
    var job: String
}

Now you can create a new user.


var user = UserStruct(name: "Hijazi", age: 20, job: "Developer")
user.name // Hijazi

Classes and Stuctures are almost the same thing, except that the struct automatically provides an default initializer for all properties, the class don’t. You don’t need to assign a value to all properties. For the Class, you have to write an initializer.


class UserClass {
    var name: String
    var age: Int
    var job: String
    
    init(name: String, age: Int, job: String) {
        self.name = name
        self.age = age
        self.job = job
    }
}

A struct is a value type. It gets copied if you pass it around. Now we have two separate objects. userB is a duplicate of userA. If you change a property of userB, userA won’t change.


var userA = UserStruct(name: "Hijazi", age: 32, job: "Designer")
var userB = userA
userB.name = "André"
userA.name // Hijazi

A class is a reference type. That means it gets referenced if you pass it around. If we change the name of userB, userA also change.


var userA = UserClass(name: "Hijazi", age: 32, job: "Designer")
var userB = userA
userB.name = "André"
userA.name // André

Comments

Comments are not always necessary as long as your code is readable and concise, and that there is no magic going on. A lot of iOS developers that I’ve worked with don’t like comments because it adds distractions to the code. But for complex logics, it’s okay to comment.

Single line comment


// My comment

Multi-line comments


/* This is a comment
written over multiple lines */

Code Sections

Xcode has a pretty useful way to browse code. You can click on the navigation bar of your code editor and search by typing the word. It is recommended to put similar functions together in your Class file and give them a section title.

Marking your section:


// MARK: Section

Naming Convention

In this book, we’re going to follow the Apple standards of naming things.

For variables and functions, we’re going to use camel case starting with a lowercase.


name
userName
changeColor()

For Classes and Structs we’ll capitalize the first letter. Notice that ViewController.swift is a Class.


ViewController
UserProfile
Comment

Avoid using abbreviations. Your code has to be readable by anyone. It has to read like English.


var u = UserProfile()

What the hell is “u”? Just like in design, don’t make your code ambiguous. Make it clear, clean and functional.

That’s it, we’ve learned some Swift basics. We’re going to use all of this for the making of our app. It’s okay if you didn’t understand everything, at least you have some idea of what they when you encounter them. You’re definitely going to get better with practice.