WWDC2014 Session 402

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Hello, welcome.
Thanks for joining us for
an introduction to Swift.
Before we get started, I want
to share you a little,
a little fact.
So we announced Swift
yesterday at the keynote and,
as part of the announcement,
we made available to
you this document.
It's the Swift Programming
Language.
It's the guide and reference to
the language and it's available
in the Doc Viewer online but
also in the iBooks Store.
And something really
remarkable happened.
From the time that we made it
available yesterday we've had
370,000 downloads.
So, yes, thank you.
Anyway, this is "Introduction
to Swift".
I am Tim Isted and I'm
joined by Dave Addey.
This is the first of three talks
on the Swift language this,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is the first of three talks
on the Swift language this,
at the conference, and
we're focusing today
on a broad overview of the
language, giving you as much
as we can, a few
little teasers of some
of the more advanced features.
Before we get started let's
go back in time a little way,
so many, many decades ago.
This program appeared
and it printed "hello,
world" for the first time.
It is, of course, the
introduction to K&R,
Kernighan and Ritchie's C book.
But many decades, that's quite
a long time in computer terms.
So what's changed in that time?
Ahh. This becomes much shorter
in Swift, yes, thank you.
So, what's happened
in this time?
Well, we've got rid of
the include statement.
There's no need to bring
in the standard library.
It should just be there.
We should just be able to
print and it should just work.
What about Main?
Well, this entire slide,
this single line of code,
that is a complete program
right there and for something
like this we shouldn't need
to have to specify, you know,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
like this we shouldn't need
to have to specify, you know,
"This is the entry
point for the app."
So we don't have to.
Because then it's
not a function.
We're not returning any random
values anymore and last,
but not least, no semicolons.
So that's Hello World.
It's a very simple app.
It's a little bit simpler
than what we all
write day in, day out.
So, what are we going
to cover today?
We're going to focus on
syntax in some key areas:
how Swift makes your code safe,
makes it much easier to read,
write, more concise,
look at some
of the modern features we've
introduced and the consistency
between declarations and all
of the syntax that we have and,
of course, how Swift gives
you extra power to do things.
To kick us off I'm going
to hand over to Dave Addey
to take us through the basics.
>> So I'd like to start with
some of the, the fundamentals
of the Swift language.
Let's start with
something really simple.
Let's define a variable.
So we do this with the var
keyword and then the name,
languageName in this case,
and a colon and the type.
And this colon appears
quite often in Swift.
This means, "is of type."
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This means, "is of type."
So languageName is
a type string.
So we'll give it an initial
string value to start us off.
Now I say initial value
but there's one thing you might
notice about this variable:
it doesn't vary so
there's no real need
for this to be a variable.
Instead, we can define
it as a constant
with a let keyword instead.
And if we introduce a
few more of these things,
let's have the version of the
language: that's a Double, 1.0.
We'll have the year
it was introduced:
that's an integer, 2014.
And the fact that the
language isAwesome?
that's a boolean
and clearly true.
Well, the year the language
was introduced and the fact
that it's awesome, these
also aren't going to change.
So they may as well
also be constant.
And this is a general
principle in Swift,
that we prefer immutability
or constants by default
and only really opt into
mutability or variables
where things actually
need to change.
Now this makes your code safer
in a multi-threaded
environments.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in a multi-threaded
environments.
It also means that Swift
can optimize your code more
effectively because it knows
what isn't going to change
and it just generally makes
your code more readable,
makes your intent clearer
that you're saying what is
and isn't going to vary.
So here I created
a string, a double,
an integer and a Boolean.
And it's pretty obvious
from these values
on the right-hand side what
it is that I want to create.
In fact, it's so
obvious from the values
on the right hand side that
there's really no point
in me writing the types.
And in Swift, in many
cases, you don't need to.
Swift uses type inference
to look at the values
on the right-hand side that
we've assigned and work
out what type these
things should be.
Now this is, this makes code
safe without the effort.
This means all these constants
and variables are explicitly
typed but you don't have
to write a ton of code to
get those types in place.
One more thing on constants
and variables before we move on
and that's that you can
use pretty much any Unicode
character you like
for your constant
and variable names,
such as pi here.
And, yes, [applause]
that does include emojis.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And, yes, [applause]
that does include emojis.
This is the stuff that
matters, seriously [laughter].
So that's some of the basics.
Talking of Unicode we
also have a modern,
fast Unicode string
implementation called,
suitably enough, String
and as we just saw
if you're initializing a
string from string literal,
as we are here, Swift
infers the times for you.
It's clear you want
this to be a string.
Now, Swift's string
syntax is very lightweight.
It looks a lot like a C
string but it's as powerful
as NSString and,
indeed, if you're working
with foundation you can use a
Swift string anywhere you would
use an NSString.
So here we're setting
the HTTP method property
of an NSURL request
using a Swift string.
Moreover, if you're working
with Foundation you have the
entire NSString API available
to you on any Swift
string you create.
So we can call the
pathComponents property
on this string and get back an
Array of the components therein.
Now every Swift string is
a collection of characters
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now every Swift string is
a collection of characters
and you can use a for-in loop
to iterate over those characters
such as here, we're printing
the five characters in the word
"mouse" on five lines.
This works just as well in
English as it does in Icelandic
or Russian or Chinese
and even with emoji.
So if you want to create a
character, you can do so just
by assigning a character
annotation to the string,
the string literal
that you've assigned.
This says we want this string,
that we want this string literal
to be a character not a string.
If you want to add together two
characters you could do so just
with addition and this goes for
two characters making a string,
it goes for strings
and characters making longer
strings, likewise 2 strings.
But sometimes we want to
make more complex strings
than just addition,
so let's say we want
to take these 2 constants,
a and b, which are inferred
to be integers from these
default values of 3 and 5,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we'd like to make this
string, "3 times 5 is 15"
but in a way that would
work for any values of a
and b that we pass in.
Now Swift has a really
elegant way to do this,
a really powerful way
of writing these kind
of more complex strings,
known as string interpolation
and this is how it looks.
And we can insert constants and
variables and even expressions
such as "3 times
5" here directly
within a string literal just by
wrapping them in parentheses,
escape with a backslash and it's
really clear what this string
interpolation will make
when it's evaluated.
It makes exactly the
string we'd expect.
And this works with
any value of a and b.
Now you might be wondering
does Swift have a mutable
string type?
And the answer is actually
it doesn't need one.
Instead, string mutability is a
case of working with a variable,
in which case the
string can change,
such as adding another string
on the end or, alternatively,
working with the constant
in which case the
string can't change.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in which case the
string can't change.
It's actually a compile
time error to try
and add another string
onto this constantString.
So that's string.
What else do we have?
Well, we have collection times,
Array and Dictionary and,
in the same way we saw,
you can use a Swift string
and an NSString interchangeably
with APIs.
You can use an Array anywhere
that takes an NSArray,
and a Dictionary anywhere
that takes an NSDictionary.
In fact, earlier on when we
called the pathComponents
property on our Swift string
what we got back was actually an
Array not an NSArray even
though the API here is defined
to return an NSArray.
Now the easiest way to create a
new collection is with a literal
and Array and Dictionary
literals
in Swift are very
familiar from Objective-C.
Arrays are just square
brackets around the edge,
commas between the items.
Here we have an Array of four
string values, four names.
Dictionary literals,
also very familiar,
colons between the
keys and values,
commas between the
key value pairs,
square brackets around the edge.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Here we have keys,
which are strings,
the names of some animals,
and integer values,
the numbers of legs
that those animals have.
So these literals are
very familiar but Array
and Dictionary actually have 2
things that are quite different
from NSArray and NSDictionary.
The first is they can
work with any type.
Here we have strings and
integers in our collections.
They don't have to be objects.
They don't have to
be a Class type.
The second difference
is that in Swift,
collections are types
collections.
Let's see what that means.
So here's our Array of names and
it's an Array of four strings.
Now, it's pretty clear from
looking at this Array of names
that it would be odd to add
an integer into this Array or,
or a Boolean value,
or a bicycle.
That would be just odd.
An Array of names
should always be strings.
So it would be nice
to have a way to say
that it can only always be
strings and in Swift we can.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We can provide a
type annotation.
This is how we write
an Array of strings.
String followed by
two square brackets,
and then we can only put
strings in this Array.
But from the thing
on the right-hand side
here it's pretty clear
that we want an Array of
strings just from looking
at this literal, and so
if we initialize an Array
in this way we actually
don't need to write the type.
Swift can infer it for us and we
still end up with a typed Array.
The same goes for dictionaries.
Here it's clear we want
string keys, integer values,
and Swift can infer this
type for us as well.
This, the fact that we have
typed collections makes code
safe for two reasons.
Firstly, it means you know
what you're going to get back.
You now what you'll get
out of these collections.
It also means that you
can't insert the wrong kinds
of things by mistake.
It's actually an error to, to
insert the wrong kinds of things
into these Arrays and
these Dictionaries.
So, having defined
our collections,
it would now be useful
to loop over them,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
it would now be useful
to loop over them,
to iterate over their values.
And we have all the loops
you'll be familiar with from C.
We have while loops, do
while loops, and for loops.
And as we saw earlier, we
also have the for-in loop,
which we use with
strings and characters
but it's a bit more
powerful than just strings.
We can use it for a few
more things than that.
We can use it with ranges.
This is a way to write a range
that includes the
numbers at both ends.
Here it's 1...5.
That's known as a closed range
because it includes both one
and five in that range.
Here, we're just printing
the first five items
in the four times table.
Sometimes, however, we want
to arrange the start at zero
and count up to but not
including the final value.
We have a way to
write that as well,
just using two dots
rather than three.
So this counts from zero to
five but not including five.
It's known as a half
closed range.
It includes the value
at the beginning
but not the one at the end.
We can use for-in with an Array
so to print a nice welcome
to the four people
in our names Array,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the four people
in our names Array,
and we can even use
it with Dictionary.
Now note here that we're
extracting the key and the value
at the same time in
a single for-in loop.
This makes for much
more expressive code
when working with dictionaries.
Now this combination of key
and value wrapped together
in parentheses is an example
of a Swift feature
known as a tuple.
And these are groupings
of values grouped together
as a single, compound value
that you can pass
around in your code.
And we'll come back to tuples
later in the session to see
where else they can be useful.
So that's how we
create collections
and how we iterate them.
How do we modify them?
Well, let's start with an Array.
Here's a shopping list,
contains 2 items, eggs and milk.
As in Objective-C we can
access the first item
in the Array just
using subscripting.
Here we're extracting eggs.
If we want to add an item to the
Array, we literally just add it
to the Array, we
add it to the end.
Here we're adding a
third item, flour.
We can also add multiple
items in one go just
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We can also add multiple
items in one go just
by adding a compatible Array.
Here we're adding cheese,
butter and chocolate
spread to our list.
If we want to change a
value subscripting again;
we just assign a new value
for an existing Array.
Here we're changing
eggs to be six eggs.
And if we, if we want to make
our shopping list a little bit
healthier perhaps,
we can actually replace
an entire range in one go.
So we can replace items three
through five, that's the cheese,
the butter and the
chocolate spread
with some bananas
and apples instead.
So that's, that's Arrays.
What about Dictionaries?
Well, we can modify.
Here's our Dictionary
from earlier.
We have three key value
pairs for animals and legs.
And so we start off
with three but we want
to add a new animal
to this Array.
This is as easy as just
assigning a new value
for a key that's not
already in the Dictionary.
Here we're adding the fact
that spiders have 273 legs.
But there's a problem.
Spiders do not have 273 legs.
If you find one that does,
run away [laughter] although
be warned it will probably
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
run away [laughter] although
be warned it will probably
catch you.
But this is not a problem.
We can fix it.
We can just assign a new
value for an existing key
and change the value
in the Dictionary.
Spiders now have eight legs.
So that's how to
modify a Dictionary.
But what, what if we want
to retrieve a value
from this Dictionary?
What if we want to see if our
Dictionary contains the number
of legs for an aardvark, or
perhaps the number of legs
for a dugong, or maybe
the number of legs
for a Venezuelan poodle moth?
Well, our Dictionary might
contain the number of legs
for these animals
but it might not.
There might be no value at all
and we need a way
to model this fact.
And this is a really
good use case
for a really powerful feature
in Swift known as optionals.
I'd like to invite Tim back up
to tell you more about optionals
and some other power features
that take us beyond
the basics [applause].
>> Thank you, Dave.
So, I'd love to use Venezuelan
poodle moths as my examples
but I actually find that
quite hard to say so I'm going
to stick with aardvark.
How do we get the
number of legs out?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
How do we get the
number of legs out?
Well, we can subscript
and we can query this
but what should we get back?
Well, we kind of want to be able
to get two types of thing back.
We either want the number
of legs as an integer
or we want something that
says this value wasn't found.
So, that's something else.
We could use some magic
integer value like,
I don't know, zero perhaps.
But the zero is a
possible value here;
snakes don't have any legs.
So we can't use zero.
In Objective-C you might be used
to using things like NSNotFound
or minus one and, you know,
we could use minus one here.
As far as I know it's not
possible to have minus one legs
but we could be using an example
where minus one was some kind
of value we wanted back.
So wouldn't it be great if we
could use some kind of value
that didn't take up one
of the possible integers?
Well, yes.
In Swift we did this
with an optional.
It's an optional integer,
indicated here by "Int?"
It means that we either
get an integer back
or we get nothing at all.
So what does nothing
at all mean?
Well, nothing in Swift
is represented by nil.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Well, nothing in Swift
is represented by nil.
It's very different
to Objective-C nil,
it means nothing.
It means no value at all
in some optional value.
So we can test to see if this
possible leg count is nil,
to see whether the
animal was found
and if it is nil then
the animal was not found.
What if it had been found?
How would we get this value out?
How do we get that
integer out of the,
out of the optional integer?
We would, we use that by, we do
that by forcing the value out,
using the unwrap operator.
That's the exclamation
mark here.
So what I'm saying is I'm saying
set the constant leg count
to the underlying value
inside possible leg count.
That's what that
unwrap operator does.
Notice I'm not specifying
a type of leg count here.
I don't need to because
this is an optional Int.
The compiler knows that
it's an optional Int
and when I'm forcing that value
out I get the underlying Int
so leg count here is an integer.
Now I said forcing,
forcing the value
out when we're unwrapping it.
Why am I using that word?
Well, I am forcing
the value out.
If I try and unwrap an
optional and there's,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If I try and unwrap an
optional and there's,
in fact that there's no
value there, it's nil,
I'll trigger an assertion.
So I should only do this
when I know for sure
that the value is there.
Because of this, there's a
very common pattern in Swift,
which is to say, is there a
value in this optional thing?
If there is, then unwrap it,
give me the value
back so I can use it.
So common, in fact, that
we have a special syntax
for this that's much safer.
It bundles those two steps
into, into a single step.
And what this does is it says if
possible leg count has a value,
unwrap it, give it back
to the leg count constant
and then I can use it
in the block of code.
If there is no value,
block of code is skipped.
So we've seen a number of
examples of if statements so far
and if statements
in Swift look much
like they do in other languages.
There's one exception
though and that is
that there are no
parentheses here.
We can use parentheses
if we like,
but they're actually optional.
So in this case they just add
unnecessary punctuation noise
so I'm going to leave them out.
The braces though, braces
are required [applause].
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The braces though, braces
are required [applause].
And, as I can hear from
that, you're acknowledging
that this gets rid of a whole
chain of bugs that happens
with nested ifs,
sorry trailing ifs.
That, you know, "if you
have that" if statement
and then two lines of code
and you've indented
them correctly but, uh,
the second one is
still going to happen.
That's bad.
It cannot happen in Swift,
we have braces for that.
They're required.
So we can do more complex things
with if statements of course.
We can have an else if in there.
But in this case I'm matching,
I'm matching multiple values.
I'm saying if leg count
is zero then I'm printing
on my animal slithers
and slides around.
Otherwise, if it's one
maybe it hops around.
Otherwise, it walks.
So I'm matching this,
this leg count
against multiple
possible values.
Really I should be using switch.
Now switch in Swift-try
saying that,
saying that three times-is
the most powerful of all
of our control flow statements.
But let's start with the basics.
Starting with leg
count, switching on that
and I'm using case to
indicate the possible values.
Value 0 slithers
and slides; case 1,
it hops; otherwise, it walks.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
it hops; otherwise, it walks.
So use case like you do
in C and Objective-C.
Notice I'm not specifying
break here.
Cases in Swift do not
automatically fall through.
I'm also not limited to just
matching against integer values.
In Swift I can match
against objects
or read any values I like.
Imagine this is an ID action
method and I'm tracking which,
which object the user
has interacted with.
So I can switch on the
sender and match it
against different outlets and
print the suitable message.
So I can match an object.
Let's go back to
integers for a moment.
And in Swift I can be
much more expressive.
So here I'm matching multiple
values in a single case
at a time, of numbers between
1 and 13, animal limps,
even numbers between
2 and 14, it walks.
That's nice, very expressive,
but there's a problem
with this example.
If I try and compile this, I'll
get an error and the error says,
"Switch must be exhaustive."
In Swift you must include
a case or a default
for every possible value that,
that could be matched against.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for every possible value that,
that could be matched against.
So the easiest way to do that
is to supply default case.
And the reason for this is it,
again, makes your code safer.
Imagine you're writing something
that uses a state machine
and you have a big switch
statement in the middle
and you forget one of the cases.
Well, then your state machine
grinds to a halt and that's bad.
That cannot happen in Swift.
You must have an
exhaustive switch,
which means either a case
for every value or a default.
So we've matched against
individual values here.
But, what if I might want
to match against a lot of,
a lot of values, a
big range of values?
Well, I can do just that.
I can match against a range.
So this is bringing in pattern
matching now a little bit.
So here we have zero
still, no legs.
One to eight has a few legs
and this is this
closed range operator
that Dave showed you
earlier, includes both the one
and the eight, three dots.
So that matches, has a few
legs, otherwise lots of legs.
So that's an introduction
to our pattern matching.
There's a whole load more
awesomeness that you can find
out about by watching the
"Intermediate Swift" talk.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, for the examples we've used
so far we've seen
a lot of println.
What is this thing?
This is a function, it's
defined in the Standard Library,
and it prints some
value to the console.
How do we define
our own functions?
When Swift functions are
defined with the func keyword,
so you can read this as declare
a function called sayHello.
Doesn't take any parameters.
It doesn't return any values
and in this case it prints
"Hello" to the console.
Call it, as you might
imagine, sayHello().
Of course, I can
add a parameter.
Maybe I want to say hello
to someone specific.
So I can add in a
name parameter.
Notice the consistency
here, name: String.
The name is of type string.
Matches with the variable
declaration syntax
and constants as well.
So this means I can
now say, "Hello WWDC!"
Hello WWDC, and using string
interpolation, I get my name
in the, in the hello there.
In Swift, my parameter could
have a default value as well.
So let's say I usually
want to say, "Hello World."
I can add that with
"=" so "name: string"
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I can add that with
"=" so "name: string"
and has a default
value of "world".
This means I can
call the function
without specifying any name at
all, it'll say, "Hello, World,"
but I still want to say hi
to you guys, so, Hello WWDC,
I can still do that anyway.
So that's parameters passing
values into a function.
What about getting values out?
Well we return values
in Swift with the arrow.
So here I've got a new function,
it's called buildGreeting.
This time, it takes a name
and it returns a string
with a concatenation operator,
that's that "+" there.
So function returns
value with the arrow.
How do we get at that value?
I'm going to create a
constant, it's called greeting,
and I'm going to set it to the
return value from this function.
Notice what I'm not doing.
I'm not specifying the
type of greeting here.
It's very clear this
returns a string
because that's what
the function returns.
The compiler knows that.
It will infer this
correctly for us.
So we don't have
to specify it again
but we can supply
the value right there
to println and it just works.
We talked about returning
a single value.
What about multiple values?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
What about multiple values?
Well in Swift we can
return multiple values
with this tuple thing that
Dave introduced earlier.
What is a tuple?
Well, tuple is just a grouping
of, a grouping of values
and they can be of any type
and any number of values
that you want, in this case,
first tuple: three
double values.
Otherwise, we could have an
Int and a string, if I like,
or Int and a string and
a double-any combination
of things that you like.
Why do I want one of these?
Well, it's not a replacement
for a full-blown data Structure.
Sometimes you really want
a Class or a Structure
to be most explicit but
tuples are really useful
when you just want to
pass multiple values
around very simply, such as
when returning multiple
values from a function.
So in this example I have
a refresh webpage function.
It goes out, refreshes a webpage
and it gives me back
the status code.
That means an integer
code and a string message
and they get bundled together.
So I return that with
a tuple, (Int, String).
How do I get at those things?
How do I use them?
Let's create a constant.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Let's create a constant.
This time I've got two names,
also in parentheses with a comma
in between and those
get bound to the values
that come back from a function.
This means that I can
then use them individually
and print them out separately.
So we've decomposed the
tuple with these names.
Again notice, thank you,
notice that I haven't
specified types here.
Return of the function
is obvious.
We've got two values
coming back from there,
they're an Int and a string.
So these map to the names and
the compiler knows it's an Int
and a message right there, I'm
sorry, an Int and a string.
You've seen an example of
this decomposition already.
That was when Dave was showing
you enumeration of a Dictionary.
And the way that we give you the
key and the value in one go is
for each iteration through the
Dictionary you get back a tuple
pair containing the
key and the value.
So these names here, these
bind in to those returns
and then you can use
them individually in, in,
in the full statement.
So tuple decomposition is one
way to get these values out.
There's another one and that is
we can actually name the values
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
There's another one and that is
we can actually name the values
in the tuple.
So I've got this
Int and a String
but it's not entirely
clear what they are.
What about if I could name them?
I'm going to say I have a
code, which is a type Int,
and a message, which
is of type String.
Same syntaxes, parameters,
and variable declarations.
Thing is of type, type.
This means, when I
call this function,
I can now just declare a
single constant called status
and I can then grab the
individual bits out by name,
status.code and status.message
ready for use.
So that's functions.
I want to move to a related
thing now which is Closures.
Closures in Swift, much
like blocks in Objective-C.
They're just blocks of code.
You can pass them around,
they can capture values
from the surrounding scope.
So here I have a very simple
one, it's called greetingPrinter
and it's a constant, and it
has this, this, this Closure
that just prints, "Hello World!"
Again, I'm not specifying
any type for greeting printer
because it's very clear this
Closure doesn't take any values.
It doesn't return
anything either.
So the compiler will infer that
this is this thing, () -> ().
Empty parens are empty parens.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Empty parens are empty parens.
That's the type of this Closure.
It doesn't take any parameters.
It doesn't return any values.
You may think well that
looks kind of familiar,
I recommend this, this parens,
arrow, parens syntax and that's
because it looks very much
like a function syntax
and there's a reason for that.
In Swift functions are
just named Closures.
So I can call my
greetingPrinter thing just
by saying greetingPrinter ()
and it prints, "Hello World."
That's a simple Closure as
a local variable perhaps.
What about Closures
as parameters?
Well to do this,
same syntax again.
I'm going to create a
repeat function this time
and this will repeat a task
a given number of times
and the task is a Closure.
So, again, () -> ().
Doesn't take any values,
doesn't return anything,
and it will be repeated for
the number that I supplied.
How do I call it?
Let's call it twice.
I want this Closure to
repeat, be repeated twice.
So I can supply my
Closure inline right there
in the function call.
Don't know about you, not
so keen on that syntax.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Don't know about you, not
so keen on that syntax.
And we can do something really
special in Swift and that is
if the Closure is the last
argument to this function,
we can shift it outside of
the, outside of the parentheses
of the function call and turn
it into a Trailing Closure.
This makes the code
much more readable.
It looks like a control
close statement now,
which it is in this case.
And, much more readable,
much more modern bringing
Trailer Closures in.
So that's Closures.
We've talked through functions.
We've talked through tuples.
To take us forward I'm going
to hand back Dave to go
through data types and
specifically Classes [applause].
>> So let's take a look at how
to define a Class in Swift.
We do this with the class
keyword followed by the name
of the class you want to create.
Here I'm going to
create a vehicle.
And all of the class's
definition,
all of its implementation,
appears between these curly
braces, all of its properties,
all of its methods, all of its
initializers and we'll see how
to write all of those
in just a moment.
But first, there are two
things you don't have
to write in Swift.
You don't have to import
vehicle.h and the reason is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You don't have to import
vehicle.h and the reason is
because Vehicle.h
does not exist.
Swift doesn't have header files.
There's no need.
Instead, you just write your
implementation for your class
and that becomes its
interface as well.
There's no need to duplicate it.
The second thing you don't
have to write is we don't have
to have a base class for Vehicle
because Swift doesn't have
a universal base class
that every class must,
must, must come from.
And you can still use
NSObjects or any of the Cocoa
or Cocoa Touch Classes
if you wish, that's fine.
But you don't have to.
If it makes sense for
vehicle to be a base class
for some hierarchy of classes
in your app then it can be.
It can be its own base class.
When we want to create a
subclass ourselves we do this
by providing the subclass
name, followed again by a colon
and then the thing we
want to subclass from.
And we'll come back to this
bicycle subclass shortly
but first let's add
a bit more detail
to our base class,
to our vehicle.
So we'll start by
adding a property,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So we'll start by
adding a property,
a property called
numberOfWheels.
It's a variable property,
default value 0.
Know that this is exactly
the same syntax we would use
if we were declaring
this as a variable,
just move into class context.
Here we've made it be
a variable property,
what we'd call a read/write
property in Objective-C
but it could be a constant.
In this case, and we just
use let, same as we would do
for a normal constant.
But we'll keep it as a
variable for now because we want
to change its, change its
value for some subclasses.
Now big, big difference
that we have in Swift
from Objective-C is that we
don't have any distinction
between instance variables
and properties in Swift,
they're one and the same thing.
And, in fact, this var
numberOfWheels = 0 is all you
have to write to
define a property.
Swift provides the
backing store for you.
You don't have to
define it yourself
and it handles all access
to that backing store
for you as well.
Now, in this case, were we just
storing a value, these are known
as stored properties but we do
have a second kind of property
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
as stored properties but we do
have a second kind of property
as well-known as
computed properties.
Let's add one of those to our
Vehicle, our Vehicle class.
So this is a computed property
that provides a description
of our class, just
a string description
of the number of wheels it has.
Note that computed properties
don't have a backing store.
Instead, they, they
generate or calculate a value
when they're called and to
write one we provide the type
that we want this
property to have
and then just return a value
of the appropriate type.
Here we're using
string interpolation
to return the number of wheels.
Now, in this case I've provided
a read-only computed property,
which is why it only
has a getter here,
but I could also
provide a setter as well
if I wanted it to be read/write.
It doesn't really make
sense for this description
to be read/write though.
It's generated based on
other properties so I'm going
to keep it as a read-only
property.
Where a computer
property is read-only,
you can actually lose
the get and the braces
and just return a value directly
from the outer description
of the computed property.
The end result is the same,
you just don't have to write
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The end result is the same,
you just don't have to write
that extra level of nesting.
Note, however, that computed
properties, even read-only ones,
do need to be defined
as variables.
Even though you can't set
them, their value can change,
it can vary, so they
need to be variables.
Now that we've created
our vehicle
and we've given it
a few properties,
let's create a new
instance of that vehicle,
which we do with
initializer syntax.
This is the name of the
class followed by a pair
of parentheses, creating a
new instance of this class.
Because we provided a default
value for our stored property,
it's clear what to do
when initializing this.
Just set numberOfWheels to 0.
Note that we didn't need
to write alloc at the point
that we created this instance.
Swift handles all of the
memory allocation for you.
There's no need to write alloc.
We also didn't need
to write the type.
Once again, Swift can infer
the type we want to create.
It's clear from the thing
on the right-hand side
that we want this
to be a vehicle.
As I mentioned earlier we,
we have these default values.
Now, this means we
actually haven't had
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, this means we
actually haven't had
to write an initializer at all
because it's just
clear what to do here.
It's clear to create
a new instance,
give it the default value of 0.
Now that we've created our
vehicle instance we can use dot
syntax to, to access
its properties,
so to print its description
perhaps.
And we can see that it has
a description of 0 wheels.
If we had changed
them, the wheels to 2,
we can see the description
change.
It now has two wheels.
But it would be nice to create a
class that always has two wheels
by default, our bicycle
subclass from earlier.
So let's see how
we'd, how we do that,
how we'd make it
have two by default.
Now, because we want
bicycle to change the value
of an inherited property, we
do need to write an initializer
and this is how we do it.
The init keyword followed
by a pair of parentheses
and these can contain parameters
so you can use parameters
to customize your
initialization,
and they look just like the
function parameters Tim showed
earlier, but we're not going
to use them in this case.
We're just going to
use a new value of 2.
Now because we're changing an
inherited property we do need
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now because we're changing an
inherited property we do need
to give our super class a chance
to set that property first,
which we do by calling
super.init,
after all it introduced
the property so we need
to give it a chance to
set an initial value,
which we may then use to
modify the value we use.
After we've done so we
can change the value,
we can set it to 2.
Now we'll go into a lot more
detail on initialization
in the Intermediate Swift Talk
but, for now, one final thing
to note: Swift initializers
don't return a value.
Rather, their main
role is to make sure
that every stored
property has a value
by the time its initialization
completes.
So now we have that set up.
We can create a new bicycle.
We can print its description,
which we inherited from vehicle,
and see it has two wheels
by default, all the,
all bicycles have two wheels.
So that changes the default
value of an inherited property
but if we want to
change its behavior?
What if we want it
to do something different
every time it's called?
For this we override
the property.
We'll create a new subclass
of vehicle called Car,
give it a new stored property
called speed, initial value
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
give it a new stored property
called speed, initial value
of 0.0 (so inferred
to be a double),
and we'll add an initializer
that sets the car's number
of wheels to be four by default.
Same approach we just
saw for, for the bicycle.
So its overrider
description: in this case I'd
like to add the speed on to
the end of the description.
We just write the,
we write the property
in the same ways we did before.
So we have that same
name and the same type.
But to do the override we
have the override keywords
on the beginning.
This makes the override
safe for two reasons.
Firstly, it makes it clear we
want to provide an override.
We haven't just accidentally
written a property
that has the same name and
the same type of something
in our super class that maybe
we didn't even know about.
Moreover, it actually
prompts Swift to go and check
that this property
exists somewhere
in our super class chain so
there definitely is something
with the same name
and the same type.
So our override will
do what we expect.
In this case we'll just
call the super description
to get the number of wheels and
we'll add an extra bit of text
on the end that shows the speed.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, if we create
a car we can see
that the description
defaults to four wheels,
zero miles per hour and, if we
change the speed, it updates.
It now includes the
new speed as well.
So that's the way to change the
behavior of inherited property
but maybe sometimes
that's a bit overkill.
We don't want to see, we don't
want to change how it works.
We just want to know when it
changes and what it changes to
and for this we have
property observers.
So to show these,
I'll create a subclass
of car called ParentsCar.
Now, ParentsCar doesn't stop
you going at a certain speed,
it just watches how
fast you're going and,
if you go too fast,
it issues a warning.
It says, "Careful now,
that's a bit too fast."
[Laughter] So to do this we
still override a property.
In this case we're overriding
the speed property we inherited
from Car.
Note that this override
is for stored property,
not a computer property,
but it's still written
in the same way.
This time, however, we won't
provide a custom getter
and setter, we'll provide either
willSet or a didSet observer
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and setter, we'll provide either
willSet or a didSet observer
and willSet is called
just before didSet just
after the value changes.
WillSet gets a newValue
constant that you can use
within the body of
the subserver.
didSet gets an oldValue constant
so that you can see what the
value was or has just changed
to be within these observers.
In this case we'll just
use willSet and we'll use
that newValue constant to keep
an eye on the speed of this car
and if it goes over 65 miles
an hour we'll issue a warning,
careful now.
So that's how we add properties.
What about methods?
How do we add methods
to our Classes?
Well, here's a simple
class called Counter.
Just keeps track how many
times something has happened.
Does with a stored property
called count and in the same way
that this stored property
looks just like a variable,
methods in Swift look
just like functions,
the ones that Tim
introduced earlier.
Here, this increment
method looks just
like we'd write a
function of the same type.
In this case it just adds 1 to
count each times it's called.
If we make it a bit more
complex, if we add a parameter,
again, it's just the same
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
again, it's just the same
as the function parameters
we saw earlier.
Know that when we refer to
count here, we don't have
to use self.count
inside the method
because it's clear what
we're referring to.
There's no ambiguity here.
The one time we do
need to use self is
if we have methods whose
parameter name is the same
as a property name.
Here we have a method with
a parameter called count.
So in this case we use
self.count to refer
to the property and count
refers to the parameter.
So that's how we create classes,
how we give them properties,
how we give them initializers
and how we give them methods.
I'd now like to invite Tim back
up to take us beyond classes
and to show some of the other
data structures you can create
in Swift to make the
building blocks of your apps.
Thank you [applause].
>> Thank you.
So beyond classes,
where should we go next?
Let's go to structures.
Structures in Swift are defined
using these struct keywords.
So here I'm going to define
a couple, maybe three.
I've got a point, it has
an x and a y coordinate,
size with a width and a height,
rectangle with an
origin and a size.
With structures I get a very
handy memberwise initializer
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
With structures I get a very
handy memberwise initializer
by default.
This means it's really
easy to create instances
of these Structures
just by supplying values
for the properties in line.
So, supplying an x and
a y, width and a height,
point and a size
for the rectangle.
If I really wanted to, I
could actually provide custom
initializers in my Structures.
To find out more about
that check out the
"Intermediate Swift" talk.
OK. So this is a
simple structure.
It has an origin
and it has a size.
Those are two, two properties.
It would be rather nice
if I could add an
area to my rectangle.
That sounds like a
computed property
so can we add one of those?
Yes, yes we can.
So here is an area
property on my rectangle,
just returns the width
times the height.
OK, properties are great
but what about methods?
Sometimes I want more
than just a property.
Well, in Swift a structure
can have a method as well.
So here I have an
isBiggerThanRect(other:
Rect) method and I can
pass in a rectangle
and return a value back
that indicates whether it's
bigger than the other one.
So structures in Swift,
incredibly powerful,
a lot more functionality
than you're used to in C.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
a lot more functionality
than you're used to in C.
So that raises the question,
what is the difference
between a Structure and a Class?
Here's a couple of examples.
We've got a rectangle, that's
at the moment a structure,
and we've got a window.
It's a hypothetical
Window class that refers
to some user interface object.
How do you determine
whether you want a class
or a structure given
that you've got a lot
of the same functionality?
Where there are two
primary differences
between classes and structures.
The first difference is that
structures cannot inherit
from other structures.
The second difference is how
values are passed around.
So let's look at our window.
I'm going to create a window;
that means I get
the window object.
All right, now this is a
reference to that object.
But what if I declared
my window as a structure?
Well, structures
are passed by value.
That means the values are copied
when they're passed around.
So my setup function here
would get a copy of my window.
That seems weird.
What would happen?
Well, I'd probably get a
second window on screen
and that doesn't
feel right at all.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and that doesn't
feel right at all.
So window, it should be a class
because classes are passed
by reference in Swift and that
means my setup function gets a
reference to the
window that I gave it,
it's a reference to this object.
OK, so that's classes.
What about structures?
Well, let's look at the
frame of the window.
It's a rectangle.
And I want to get this frame,
I want to do something to it,
and I want to use
it somewhere else.
So I'm going to extract it
into a variable, newFrame.
What happens if rectangle
was actually a class?
Well if I set the origin here,
that's actually going
to affect my window.
Clearly, that's not
want I want to do.
I just want to change this
and use it somewhere else
and it's covering up my
slide so, clearly bad.
So the window's frame is a
rectangle and the rectangle,
that should be a value
type, a structure.
Structures are passed
by value, they're copied
around when they're
passed around.
So we talked about
the difference
between reference
and value types.
Let's look at constants
and variables
with these things in mind.
Let's say I create a window
and this time I declare it
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Let's say I create a window
and this time I declare it
with a let keyword, that
means I have a constant
window reference.
What does that really mean?
Well it means that I have a
reference to a window object
but the window object isn't
affected by this constant.
It's only the reference that is.
So I can still change my
window's title quite happily.
I can still set that to "Hello!"
and it just works.
But, it's a constant reference.
That means if I try and
connect this reference
to a different window I'll
get a compile time error
because I cannot mutate
a constant and I'm trying
to mutate the constant
reference here.
What about value types?
Let's start with a variable.
I'm going to create a variable
point1 and, for a value type,
try to think of it as a
big value in and of itself.
The whole thing is a value.
A point is an x and
a y coordinate,
so this point1 has an
x and a y in there.
If I change my point1.x it's
going to update that value
and set it to 5 and that's fine,
it's a variable, it can do that.
But if I use let
to declare point2,
the entire value
is now immutable.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the entire value
is now immutable.
That's now constant.
That means I cannot set
point2.x, the x coordinate there
because I cannot
mutate a constant.
The entirety of that
value is constant.
Hmm. So, whether or not I can
mutate my value type depends
on the declaration used.
So what does that mean if I want
to add some kind of a method
to my Structure that,
that changes it?
Let's say I want
something that moves a point
to the right by a given number.
Well, that's changing the value.
So I shouldn't be able
to do this on a constant.
If you do want to do this then
you must declare the method is
mutating and it tells
the compiler
that you're changing
the underlying value.
That means, if you declare
a point with a constant
in this case and
you try and move it
to the right you'll get an error
because you cannot
mutate a constant.
Structures, that's one example
of a value type in Swift.
Another one is enumerations.
So enumerations in Swift can
have raw values much like C.
So here I have a
planet enumeration
and it has a raw value of Int.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So I'm using a 1-based index.
Mercury is the first planet.
Venus is the second.
I could use 0 if I
wanted but I want 1.
So Earth must have
some, some value.
How do I determine
what that value is?
Let's create a constant,
EarthNumber, and I'm going
to set it to raw
value of Planet.Earth
and that will give
me back three.
That's how I get the
raw value back out.
So I can use integers
as an underlying value
but in Swift I can use
other types as well
such as a string or
maybe a character.
Here I can now name
the tab, linefeed,
and carriage return
characters with using an enum.
But sometimes it
doesn't make sense
to have an underlying
value at all.
Sometimes the cases are just
values in their own right.
So here I have a compass point.
It has north, south,
east and west.
There's no real number or string
that really makes sense to tie
to these so they're just values.
They're just values
in themselves.
So how do I work with them?
Let's create a directionToHead.
It's a variable.
I'm going to maybe
change that in the future.
And I'm going to set it
to CompassPoint.West.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And I'm going to set it
to CompassPoint.West.
Compiler will then say
oh, it's a compass point.
So it knows that directionToHead
is a compass point.
Let's say I'm following
some directions
and I change direction,
I want to head east.
How do I saw that?
Well, because the compiler
knows that it's a compass point,
all I have to say is enough
to change that to east,
which is .east in this example.
This works extremely
well when you're working
with Cocoa Touch and Cocoa.
We've done some incredible
magic when we've imported things
over into Swift, so that if
you're dealing with a UILabel
for example and you want to set
the text alignment property,
in Objective-C you do that
with NSTextAlignment right.
But the compiler knows text
alignment is NSTextAlignment,
that is the type, so all we
need to do is supply enough
to specify that it is right.
So the text alignment is now
right, much more readable,
much more concise,
super awesome.
Enums can have raw
values, underlying values,
no values at all but there's a
different type I want to talk
about and that's enumerations
with associated values,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
neither are discriminated
unions.
So to give you an example,
let's consider a train.
Trains are usually one of two
things, they're either on time,
sometimes, or they're delayed.
If they're on time, they're just
on time but, if they're delayed,
they're delayed by
a number of minutes.
So in this case we have
(Int) after the delayed case.
And this says that I want to
be able to, to catch both,
either on time or the
delay and the number
of minutes that it's delayed.
Let's see how we work with that.
I'm going to create a status
variable and I'm going
to set it's initial value
to TrainStatus.OnTime.
The train's very optimistic,
he always starts on time but,
as we all know, sometimes stuff
happens and they get delayed
and so we can change that just
by saying, hey, it's now delayed
and we can supply the value,
42 minutes, right there.
So that's an associated value.
Very powerful but we can,
we can do more than this.
I'm going to add a little
bit more functionality
to my train status and I'm gonna
start by adding an initializer.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to my train status and I'm gonna
start by adding an initializer.
This means that when
I declare something
that uses this train status
it will automatically get the
onTime status by default.
I'm not going to
stop there though.
Let's add a computed
property called description.
This time I'm going to
determine what the value is
and then give back a string
that means something sensible.
So if it's on time it
will say, "On time."
If it's delayed, I'm going
to grab the number of minutes
that it's delayed by by binding
minutes in here to the number
and then I can build
a string using
that with string interpolation.
So enumerations are
hugely powerful here.
How do I work with this
thing once I've done this?
Well, now I can delay,
I can declare it
with status = TrainStatus().
That'll give me an
on-time status by default.
So if I print the description
it will say it's on time
but then it gets delayed, hmm.
And so I can set
the delay and now
when I call description it will
give me "delayed by 42 minutes".
But this status is very
much tied to a train.
It's very likely that the
only place we really use this
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's very likely that the
only place we really use this
in our app is inside
some kind of train class.
It seems a bit of shame
to have it just floating
around for anyone to use,
or at least making it super
easy for anyone to use.
Wouldn't it be nice if
we could tie our status
into the train class itself?
Well in Swift we can do
that by nesting the type.
So we can grab, we can put our
status inside the train class,
nest it right there.
So now it's just called Status
because it's inside the train.
Set up as before.
I can still have a property
on my train that is of this,
of this status and it will
be set to OnTime by default
and we can just use it.
So we can nest types in Swift.
Let's move on to more power.
I like power.
Extensions.
So an extension in Swift,
very much like a
category in Objective-C.
We can extend any Class we like.
But in Swift we can go
a little bit further.
We can actually extend
any named type we like,
including value types.
So here I have my Size
structure you saw earlier,
that's a structure.
And I'm going to add
this mutating function.
It increases the size
by a given factor
because it changes the
underlying values I've marked
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
because it changes the
underlying values I've marked
as mutating.
But I'm not just limited
to named types that
I have in Swift.
I can actually also extend
any name type I have available
to me.
So here I'm extending CGSize,
that's from Core Graphics.
It's a structure defined in C to
add the same increaseByFactor.
When I've done that,
it's available anywhere
in my Swift code
from this extension.
So that's extending
a named type.
I want to see what else
I can do with this.
Wouldn't it be fantastic if
I could extend, hmm, an Int?
Well, yes it would
and let's do that.
Int is just a structure
defined in the standard library
so I can extend it and I'm going
to add a repetitions function
to my integer and this is going
to take a task, a closure,
and it's going to
repeat it to how,
whatever value the
integer is, 0..self,
that will give me the number
of repetitions I need.
So now I can supply
closure on the call
to repetitions on
any integer value.
So I can say, for
example, 500.repetitions
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So I can say, for
example, 500.repetitions
and then supply closure
and I'll get "Hello!"
printed 500 times [applause].
But there's more.
Because, because the
closure is the last argument
in this function call, I can
hoist it out, put it outside
of the parentheses
and, you know what?
For training closures, if there
are no other arguments I don't
even need the parentheses.
So this turns
into 500.repetitions do this
thing like Control Flow.
So I just extended an
Int, a value type Int
from the Standard Library.
How amazing is that?
And as we head more into kind
of blow your mind territory,
I'm going to leave you with one
more thing and that's generics.
So let's start with a
non-generic example.
Here I have a stack of
integers, it's an IntStack.
And I can push values
onto the stack
and I can pop them off again and
that's, that's great but what
if I wanted a double
stack or a string stack?
Or, hell, even a
stack of stacks?
How would I, how would
I, how would I do that?
Well, I'd have to duplicate
this definition multiple times
and the only thing I would
change would be these
highlighted bits, the
Ints across there.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
highlighted bits, the
Ints across there.
That's the types used for the
Array and the two functions
that I have, the two methods.
Wouldn't it be lovely if I
could just say, you know this,
this should work
with any type at all?
We can do that with a generic.
So generics in Swift,
you indicate the type
with these angle
brackets and so
that says there is a
generic-type parameter here
and anything that uses this
T, that must be the same type.
So elements is just
an array of Ts.
Push now takes a T,
pop now returns a T.
What does that mean?
It means that we can now build
our stack of Ints like this.
We can just say create
stack of Ints, push on 50,
notice I'm not specifying
anything
and here the compiler knows
that push must take an integer
if it's a stack of Ints.
So I'm pushing 50 on.
I can pop that off and it knows
that lastIn will be of type Int
because that's what
I'm dealing with.
What about strings?
Well, I can use this
with a string as well,
so now I can create a string of,
uh, a stack of strings and push
on a string, again, compiler
knows it can only work
with a string and when
I pop it off it knows
that I'm returning a string,
therefore I can print it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that I'm returning a string,
therefore I can print it.
So that's generics.
It's a very, very brief
introduction to generics.
To get further details on all
of the awesome stuff you can
do you should check out the
"Advanced Swift" talk.
That brings me on
to a question then.
How do you learn Swift?
How do you go and figure out
all the cool stuff you can do
with this language?
Well, as we saw up front,
this book is available.
It's in the Doc Viewer,
it's online.
It's available in
the iBooks Store.
The Swift Programming Languages:
it's the canonical guide
and reference to the language.
We also have Using Swift
with Cocoa and Objective-C.
This is a document that tells
you how to work with Cocoa
and Objective-C from
existing code,
how Swift interoperates
with Cocoa.
For more information
on the language itself,
check out the intermediate
and advanced Swift talks.
And for more information
on Objective-C
and interoperability, check
out the two "Interoperability
in Depth" and "Integrating
Swift with Objective-C" talks.
We are in labs all week.
Come down, tell us
what you think.
We want to hear your questions.
If you're playing along at home,
talk to this guy, Dave DeLong.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you're playing along at home,
talk to this guy, Dave DeLong.
He's our evangelist.
Check out Developer Forums.
Thank you very much.
That is Swift.
[ Applause ]