Updated to include the latest features, syntax and best practices for Swift 3, this session introduces the basics of the Swift programming language. Learn the recommended manner in which to declare variables, define functions, work with fundamental value types, protocols, generics, and more. Explore some of the great features that make Swift a safe, fast, and expressive language.
[ Music ]
Hello, and welcome to Getting Started with Swift.
I'm Dave Addey, and together with my colleagues Brian
and Alex, I'd like to give you a quick overview
of the Swift Programming Language.
In the next 60 minutes you'll learn enough about Swift 3
to be able to read Swift code and hopefully
to start writing it, too.
So let's start by taking a look at some of the basics
of the language, and here's some code I wrote two years ago.
I've written a constant, indicated with let,
it's called language, and it's a string.
And this colon in the middle, you'll see this often in Swift,
this means is of type.
So language is of type string, and I've just given it a value
of Swift, using a string literal in my code.
Let's make a few more.
Let's have an integer called introduced.
We'll that to 2014.
And a Boolean called isAwesome.
And we'll set that to true.
Now, you might notice that none of these values need to change.
The language's name isn't going to change,
nor is the year it was introduced.
And two years on, Swift is still awesome,
so that can probably be a constant as well.
And this is the general principle in Swift.
If something doesn't need to change,
we declare it as a constant.
Now, you might also notice a naming trend here.
Constants and variables tend to be written as lower camel case,
and types, such as String, Ints and Bool, is upper camel case.
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 Boolean,
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.
So that's some constants.
What about variables?
Things do sometimes need to change.
So here's a variable indicated with var,
and it's for the version of the language.
This has changed.
So let's bring it up to date to 2016.
Now, if I try to do this for a constant,
if I try to set isAwesome to false, Swift would tell me
that it was an error, and quite right, too.
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, but Swift has a neater way to do this,
known as string interpolation, and this is how it looks.
And we can put strings and other values inside a larger string
by wrapping them in parentheses preceded by a backslash.
Here we're making the message, Hello WWDC.
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.
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.
You can use pretty much any character in the name
of your constants and variables.
Talking of [inaudible] characters,
Swift does all the hard work of working out what it means
to be an individual character,
regardless of how your string is encoded behind the scenes
or how it appears on screen.
So here I have a string called dogString.
You might think that this has six characters in it.
D, O, G, ?, !, dog face.
But you would be wrong.
There are five characters here, not six.
This is a special character called question exclamation
mark, which is really,
really good for expressing incredulity about dogs.
Now, if you don't believe me, let's get Swift to prove it.
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.
If we pass that to the print function,
we find out that we do, indeed, have five characters.
But if you still don't believe me, well, 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.
We have array and dictionary.
You might know dictionary as a hash
or map table from other languages.
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.
Here we have an array of four names, four strings.
Dictionaries look very similar.
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.
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.
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.
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.
Swift has all of the loops you might know from other languages.
We have a while loop that checks its condition before first
executing its body.
And a repeat-while loop,
which executes its body once before checking a condition
to see if it should continue.
And as we saw earlier, we have the for in loop, which we used
to iterate over the characters of a string.
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.
That is called a closed range
because it includes both of those numbers.
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.
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.
We can use a for-in loop with an array.
Here we're printing a message for each
of the names in our array.
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.
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.
And we'll see another example of this later on.
And it makes for much clearer code
when iterating over a dictionary.
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.
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.
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.
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.
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.
So what about a dictionary?
Let's modify a dictionary.
Well, here I have my ages dictionary from before.
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
Here I've added Justyn.
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.
What if I want to retrieve a value from the dictionary?
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.
If we tried this for Amy,
we might expect a value of 40 perhaps.
But if we tried it for Daryl, what should we get then?
There's no value here for Daryl.
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 question mark.
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.
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.
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.
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.
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.
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.
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.
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
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.
I'd now like to hand over to my colleague Brian to introduce you
to functions and closures in Swift.
Thanks, Dave, as I was saying.
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.
So let's add a parameter to the function
that indicates whether the message should be sent shouting.
You write the parameter's name, followed by colon
and the parameter's type, just like you do
when you declare a constant or a variable.
Here we've added a parameter called shouting,
which is of type Bool.
And when you call the function,
the parameter's name provides a label
for the argument you pass in.
Labeling your arguments makes your code read better
and makes the purpose or intent of each argument clear.
In this case, if you left out the shouting label,
someone reading your code later might think
that true just indicated whether the message should be sent
So you can shout a message, but who are you going
to send the message to.
Let's add another parameter that lets us address the message
to someone in particular.
So here we've added a parameter called recipient,
which is of type string,
and we've included the recipient's name
in our message using string interpolation.
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.
sendMessage recipient Morgan is pretty awkward.
When you call a function, you want it to read naturally.
In this case you'd like it to say something like sendMessage
to Morgan, which forms a nice grammatical phrase.
And you could do this by changing the name
of the parameter, which then changes the name
of the argument label, and this does make the function read
better when you call it, sendMessage to Morgan,
but it doesn't work so well inside the body of the function.
Inside the body you really want a noun for the parameter,
not a preposition, hey there to, isn't so great.
But sometimes there isn't a single word
that works well both inside the function's body and as a label
when you call the function.
In Swift you don't have to give one of these up.
When a parameter's name isn't appropriate as a label
for the argument when you call it,
you can explicitly provide a more suitable one.
You write the explicit argument label in front
of the parameter's name.
Here we've added to as an explicit argument label
in addition to the recipient parameter, and this just means
that you can use to when you call the function,
sendMessage to Morgan, and you can still use recipient inside
the body of the function.
Let's add one more parameter to the function
which lets you provide a custom message when you call it.
Here we've added a message parameter of type string.
Now when you call the function,
you can pass on your own message.
Now, once again, this code works as expected,
but it doesn't read very well either.
sendMessage message is redundant.
The message label isn't helping to clarify the role
of the first argument because it's already clear
from the base name of the function, sendMessage.
Here the argument label actually makes the code harder to read.
In the cases like these, you can write an underscore in front
of the parameter's name.
And this means that you don't provide a label for the argument
when you call the function.
And now our function reads naturally when you call it;
sendMessage, See you at the bash, to Morgan.
Now, it's not very often that we need to shout our message,
so we usually pass in false for that argument,
and in Swift you can actually capture this behavior right
in the declaration of the function.
Whenever a parameter has a single commonly used value,
you can provide that value as the default, and you do this
by assigning a default value, in this case false,
right after the type of the parameter,
and now when you call the function, you can leave
out the corresponding argument and the default value is used.
And when you're deciding whether to use or when
to use an explicit argument label, when to omit one or when
to provide default values for parameters,
remember that functions are declared only once,
but they're used repeatedly.
So the most important thing is that the function reads clearly
and concisely when it's called.
Now, to learn much more about the kinds
of things you should consider
when you're writing great Swift API,
check out the Swift API Guidelines talk.
So we've looked at lots of ways functions can take values.
Let's take a look at some of the ways they can return values.
Let's say you want to write a function
that returns a first string in an array
that has a given prefix.
The function takes a string prefix, an array of strings,
and it returns the string with a given prefix.
As you can see, you use an arrow to indicate what type
of values your function can return.
In this case a string.
So let's see how it works.
First use a for-in loop to iterate through each string
in the array and then you check whether a string has a
You need to check whether the string has a given prefix using
If it does, you're done and you can simply return the string
by writing it in a return statement.
But what do you return
if the array doesn't contain the string you're looking for?
Well, because this function was declared to return a string,
the only option you have is some valid string value,
in this case the empty string.
But this is not good Swift code.
However, as Dave showed earlier, optionals are perfect
for representing values that may be missing.
So you just need to change the return type of this function
to be an optional string by writing a question mark
after string, and now you can return nil
when the string isn't found.
And because the function returns an optional string,
you can call it safely in an if-let statement.
Now, notice that Swift infers a return type of the function,
so there's no need to write it explicitly here.
So we've looked at some of the ways functions can take
and return values of various types, such as strings,
integers, arrays and even optional types.
Let's take a look at writing one more kind of function.
Let's say you want to write a function that filters an array
of numbers based on some condition.
Let's think about what this function needs to do.
It's going to take in an array of numbers and for each number
in the array it's going to determine whether to include
that number in the filtered results.
For example, if you wanted an array that's been filtered
to contain only the even numbers here,
you could test whether each number is divisible by two.
In this case, of course, four is even,
so it's included in the result array.
If a number isn't even, such as 17,
the filtering function just moves on to the next number
to test, and so on through the rest of the array.
Now, let's look at writing this function in code.
The function declaration is what you might expect,
but what type do you put in for the includeNumber parameter?
As you saw a few moments ago, deciding whether
to include a number
in the filtered result is itself actually a function,
not just a simple value, like a string or a number,
and in Swift functions can take other functions as parameters.
So what does the type of a function look like.
Well, all function types in Swift have this basic form.
The type of the function's parameters, if any,
go inside of the parentheses, followed by an arrow
and the function's return type.
So, for example, here's our basic send message function
It has the type, empty parentheses
because it doesn't take any parameters, arrow Void.
Here void just means it doesn't return any values.
And in Swift if your function doesn't return anything,
you don't need to write the arrow Void explicitly.
And here's the firstString function.
Its signature is a little more complicated,
but its type follows the same basic form.
It takes a string, an array of strings
and it returns an optional string.
So now that you've seen this syntax for function types,
it's pretty clear how you need
to finish the declaration for filterInts.
The includeNumber parameter can be any function
that takes an integer and returns a Boolean, and you write
that type as Int in parentheses, arrow Bool.
So let's go ahead and write the rest of this function.
You need to build up an array of filtered numbers,
so here's a variable called result.
It's been initialized to an empty array of Ints.
And as you iterate through the array of numbers,
pass into the function, you need
to check whether each number should be included
in the result array.
To do that you pass each number to the includeNumber function,
and notice that inside the body of filterInts,
the includeNumber parameter is treated as a name
of the function it's passed in, and that just means
that you can call it in the same way
that you do any other function.
So that's how you write a function
that takes another function as a parameter.
But how do you call one of these kind of functions?
Well, first you're going to need some values
to pass into filterInts.
So here's an array of numbers
and a simple function called divisibleByTwo
that indicates whether an integer is even.
As you can see, the type
of divisibleByTwo matches exactly the type
of the includeNumber parameter.
So that means that we can pass the divisibleByTwo function
as an argument to filterInts.
You do this by simply passing in the name
of the divisibleByTwo function and now you've got an array
of only the even numbers.
Now, notice that you don't include the parentheses
when you pass in the divisibleByTwo function,
and that's because you're not calling it at this point.
Instead, it's called later inside the body of filterInts.
Also notice that we passed in the array of numbers by name,
but you could have passed in a literal array instead;
for instance, if you just needed to pass in a few values
without needing to create a constant for later reuse.
The same is true for passing in functions as arguments.
It's not very likely that the divisibleByTwo function will
find much reuse.
And it would be pretty cumbersome to have
to make a new function every time you wanted to pass
in a different filterInt condition.
And if you look at the important parts of divisibleByTwo,
you can see that giving it a name
at all is really just a convenience geared toward reuse.
divisibleByTwo is just a name for the functionality
that you see highlighted.
And in Swift, just as you can write a literal string
or a literal array, you can write a literal function
without a name called a closure expression
and pass it around in your code.
The syntax for writing a closure expression is very similar
to a function declaration,
except that it doesn't have a name.
You write the entire body of the closure inside
of the curly braces and you separate the closure's body
from its signature using the Int keyword,
as in use the parameter number of type Int in the body
of this closure, which returns a Bool.
Now, this is the most explicit or complete way
to write a closure, but as you've seen before,
Swift can infer a lot of information
from the context your code appears in.
For example, the function type of the closure is already known
from the type of the includeNumber parameter,
and this means you don't need to write it explicitly.
And when the entire body
of the closure is a single return statement, as it is here,
you don't need to write the return keyword either.
So this is much cleaner syntax, but because the closure's
so short, even the number parameter seems a bit redundant.
And in cases like these Swift provides implicit argument
names, so there's no need
to even write the parameter name or the Int keyword.
These implicit arguments start with dollar sign
and a number beginning at 0.
So $0 refers to the first argument to the closure,
$1 the second, and so on.
And even though these are available to use
in any closure expression, use them when doing
so doesn't make your code harder to read.
Now, you've seen that Swift provides lots of convenient ways
for writing closures,
but passing them directly inside a function's parentheses is a
little punctuation heavy.
A closing curly brace right next
to a closing paren is pretty terrible.
However, when the closure is the last argument to the function,
as it is in this case, you can write it instead
as a trailing closure right outside of the parentheses.
And as you'll see later, if the closure's the only argument
to a function, you can drop the parentheses altogether.
Now, trailing closures are especially nice
when the closure contains more than one line of code.
For example, here's a more complex closure
that determines whether the sum of a number's digits is even.
Trailing closure syntax ensures that even complex closures
with multiline functionality read naturally and elegantly.
Now, the filterInts function is pretty useful if all you want
to do is filter integers, but what if you want
to filter arrays of other types, like strings.
For example, say you have an array of names
and you want a filtered array that contains only the names
that have less than a certain number of characters.
You could do this by writing a filter string function
like the one you see here,
and since you've already written a filterInts function,
let's see whether you can reuse any of that logic.
Well, first, you'd obviously want to do some bookkeeping
and change all the places that refer
to numbers to refer to strings.
And next you need to change all
of the Int types to be string types.
And because the behavior
of these two functions is actually the same
for both integers and strings,
there's really nothing else to do.
They're essentially the same function.
And now you have this function
that filters an array of strings.
Now, if you want a filtered function that works
for other kinds of types, you can repeat this process over
and over and over again for each kind of type,
but this would obviously get boring pretty quickly.
So instead, you can write one function that works
with arrays of any kind of type.
This is called a generic function.
So let's look at how you write one.
Writing one is not much different
than what you've seen already.
First you change the names to be more generic.
So, for example, the function's name is simply filter,
rather than filterInts or filterStrings.
Next, and more importantly, you need to fill in the placeholders
that you see here with the type of the elements,
but you don't know what that type is yet.
So instead, what you really want is a type parameter.
The actual type is determined when the function is called.
Here we filled in the placeholders
with a generic type parameter called element.
And so that you can tell the difference
between type parameters and actual pre existing types
like strings or integers, you write the type parameters
up front inside of the angle brackets right
after the function's name.
And now you have a generic filter function that works
with an array that contains any type of values.
You call this kind of function in the same way as before.
You don't need to specify the type you want the function
to work with because it's all inferred
from the values you pass in.
Filtering is such a useful operation
that the Swift standard library has a filter method that works
with any kind of sequence or collection.
It works in basically the same way
as the filter function you just saw, except that it's a method
so you call it using dot notation,
names.filter, as you see here.
The Swift standard library actually has lots
of other methods that take closures as arguments.
And another really useful one is the map method,
and it also works with any sequence or collection.
Map returns a new array that contains the result
of a plan enclosure to each element.
So here's an example that calls map on the array
of short names from above.
It passes a closure that simply upper cases each string.
You can even chain these together
to perform multiple operations.
So, for example, you can perform the filtering
and the upper casing in one expression.
By chaining these two method calls together using
The filtering happens first, and then map is called
on the filtered array,
which then finally returns the upper cased strings.
And this reads nicely even
when you're using the trailing closure syntax.
So the combination of closures and functions that take them
as arguments makes it possible to write really complex,
powerful code in a concise yet highly expressive way.
So we've looked at functions and closures,
and even a bit of generic functions.
I'd like to invite Alex on stage to tell you all
about data types in Swift.
You've seen how to use existing data types in Swift.
Now let's take a look at how
to create some data types of our own.
Let's start with structures.
You create one like this.
You write the struct keyword followed
by the name of a structure.
Then inside the curly braces you write the properties
of the structure.
Properties use the same syntax you've seen before
for variables and constants.
Both properties here have the value assigned as part
of the declaration, so you can create a rectangle
by just writing rectangle, the name,
followed by a pair of parentheses.
And to access the properties, you use dot notation.
You don't have to provide a value for a property as part
of the types declaration.
In fact, most of the time you don't.
More often, you write just the type and then you set the value
when you create the instance.
So another property
of a rectangle besides its dimensions is its area.
You wouldn't want to store the area though.
You'd have to update it every time the dimensions changed.
What you want is a property whose value is calculated right
at the point you need it and you can do
that using a computed property.
To make a computed property, after the property's name
and its type, you write a function body that's responsible
for computing and returning the current value of the function.
Even though it's computed rather than being stored,
you still access it using dot notation.
There's more that you can do with properties.
You can have setters and observers, and you can find
out information about those in the Properties chapter
of the Swift Programming Language.
Just like you can define properties on a structure,
you can also define methods.
They use the same syntax you've seen already for functions.
And just like properties, you access them using dot notation
when you need to call them.
You've seen this syntax a few times to create a rectangle.
Let's look at what it does in a little bit more detail.
It looks a little bit like a function call
because of the parenthesis,
but it's actually calling an initializer.
So far we've been using a special initializer called a
member wise initializer that Swift implements
for you on structures.
Here's what it would look like if you write
that initializer out explicitly.
You write the init keyword and then inside you set a value
for the rectangle's properties.
Notice that there are two things here called width.
There's a property and there's a parameter, and you write self.
to explicitly refer to the property.
So that's how you write your own initializer.
There's enough code in this rectangle structure
that it could benefit from some organization, and one way to do
that in Swift is using extensions.
An extension lets you add functionality
to an existing type.
In Swift you can use extensions to divide up your code.
Core functionality can go in the structure's declaration
and additional functionality can go in one or more extensions.
You're not limited to extending your own types.
If you need to, you can extend types from other places,
such as foundation or the standard library.
You saw earlier how you can make a generic function
which performs the same operations
on data of different types.
You can also make a generic structure
which contains data of different types.
The syntax looks very similar.
You still have the generic type parameters inside angle brackets
after the name.
This example attaches a name to an array
of some kind of element.
This would be a useful data structure, for example,
to populate a table view that has sections with heading names.
You create a generic structure instance just
like an instance of another type.
Here you can see if you write the type annotations,
board games and primes have different types.
One is an array of strings
and the other is an array of integers.
They have different element types
so they are different types.
You don't have to write the arrays.
Swift infers what element is automatically.
So that's structures.
Another data type in Swift is classes.
You write class before the name, but everything
about structures still applies.
Properties, methods, initializers, and so on.
So why would you want to create a class?
One reason is that your code can refer to the same instance
of a class from several different places,
and that's different than the behavior you have
A structure acts like one big value.
For example, in a game, if you make a score for player1,
and then give player2 the same score,
you have two independent scores.
Changing player2's score doesn't change player1's score.
However, both players need to refer to the same file on disk
when they log their high scores.
Since it's a class, that's the behavior that you get.
When player2 gets a new high score and then logs it
to the file, both players see the change.
If you're coming from another object oriented language,
you might be used to writing a lot of classes,
and in Swift you don't need to write them
as often as you might think.
Anytime it makes sense to check for equality or to make a copy,
you usually want a value type like a structure.
For more information about how and why to use value types,
there's a great talk you can check out.
Another reason to use classes is when you need
to subclass an existing class.
For example, suppose you have a framework
that gives you this fish class with sort
of core fish functionality.
You can subclass it to add functionality,
like a FlyingFish can add a flying method.
You indicate that this is a subclass by writing colon fish.
Subclasses can also override a method
to provide their own implementation.
Like this ComplainingFish.
It swims like a normal fish, it just complains about it first.
You write super.swim to call the superclass' implementation.
This code doesn't compile yet.
When you override a method in Swift,
you have to mark it explicitly by writing override,
and now this code works.
Just like it's an error to override something by accident,
it's also an error to write override
when you don't override anything.
That means if you misspell a method name that you're trying
to override, Swift tells you
about the error right at compile time.
A segue can also provide an initializer.
For example, fish that has an initializer that takes a name.
ComplainingFish needs an initializer
with both a name and a complaint.
Inside the initializer you set the initial value
for the properties declared by the subclass,
and then you call super.init
to let the superclass finish the initialization.
There's more you can do with initializers,
especially around classes.
You can read all about it in the Initializers chapter
of the Swift Programming Language.
You've seen how you can use subclasses.
Now let's talk about a subclassing problem.
Continuing the game example,
suppose you have this player base class.
Since every player can take a turn,
there's a method to do that.
You have two kinds of players.
You have a HumanPlayer class, which takes its turn
by showing UI to the user.
And you have a ComputerPlayer class which takes its turn
by finding the best legal move.
So the question then is what goes
in the base class implementation?
Well, there's no shared behavior
between human and computer players.
There isn't any shared code to factor out.
And in the surrounding code you would never want an instance
of the player base class.
So this method should never be called.
The only reasonable thing you could write here is some sort
of fatal error to help you catch mistakes early
in the development process.
All the player class is doing is describing what it means
to be a player, that every player can take a turn.
It's a sort of blueprint for players.
In Swift you express this kind
of relationship using a protocol.
Protocols specify requirements like methods and properties.
They're like interfaces or abstract classes
that you might know from other languages.
You make one using the protocol keyword.
And because it describes requirements for other types
to fulfill, you don't provide an implementation.
Types conform to a protocol by providing that implementation
and you declare conformance by writing : player,
just like you do when there's a superclass.
At this point you're not subclassing anymore
so these methods are not overriding anything.
So you don't write override.
There's no real reason these need to be classes anymore,
so let's make them structures.
And let's take a closer look at HumanPlayer.
It has a few other properties, like a name and a score.
And if you make an instance of player, you can print it out.
You get a default description here
because the standard library has a conversion
from any type to a string.
But what if you wanted to customize the conversion
to print a nicer description?
The standard library also has a protocol called
which lets you provide a custom description, and here's what
that protocol looks like.
It has one requirement -- a description property.
Any type that conforms to this protocol uses the
Okay. So where should you implement the
Remember from earlier how you can organize your code using
extensions with core functionality
in type declarations,
and additional functionality in extensions.
Having a custom string conversion definitely falls
into the second category.
It's not core functionality, so let's put it in an extension.
Here's how you extend a type to add protocol conformance.
You write colon CustomStringConvertible
in the first line.
And then you implement the requirements inside the
Now when you call print, you get the customized
There's a lot that you can do in Swift using protocols
and extensions to organize your code and create abstractions.
For more information check out this talk
on Protocol Oriented Programming from 2015.
That brings us to the last data type in Swift -- enumerations.
You use an enumeration when there's a list of values
that you know ahead of time.
Here's an enumeration that supports left
and right alignment for text.
When you use an enumeration,
you use dot notation to access its cases.
Here there are only two cases, so it's still readable
if you write them on one line.
Because an enumeration has a list of possible values,
it's very common to use one with a switch, one switch case
for each enumeration case.
Writing alignment over and over is a little repetitive
and here it's not necessary.
The switch is considering textAlignment,
so the only possible values to check
for are enumeration cases from that alignment.
That means you can omit the enumeration name
and write just .left.
Also, notice that there's no default case here.
That's for the same reason you saw earlier.
The switch already covers every possible alignment value,
so there's nothing left for a default case to handle.
Omitting the default case has a nice advantage.
If you come back later and add a new enumeration case,
but forget to update the switch, Swift will highlight the error
until you add the missing code.
Now let's take a quick look
at two more things you can do with enumerations.
You can associate values with each enumeration case.
For example, the alignment can specify how much padding to use
and you can get that padding value back
out as part of the switch case.
You can also give each enumeration case a raw value
from some other type, such as a string or an integer,
which lets you improve type safety in your code
by using enumerations instead of string constants.
You've seen a lot of Swift this afternoon, but there isn't time
to show you everything.
One last thing I'd like to show you is error handling.
In Swift you can use an enumeration to describe errors.
You use throws to mark a function
that can throw an error.
You write defer before a block of code that must be executed,
whether or not there's an error,
and that execution happens just before exiting scope,
such as returning from a function.
Before calling code that might throw an error,
you mark it with try, and you can catch
and throw errors using catch and throw.
For all the details about error handling,
take a look at the Error Handling chapter
in the Swift Programming Language.
You can find a link to that book and other resources here.
There are lots of other great Swift talks to check
out later this week or on video.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.