WWDC2014 Session 408

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Hi. Welcome to
Swift Playgrounds.
I'm Rick Ballard and with
me today is my colleague
Connor Wakamo.
We're both Engineers
in the Xcode Team
and we've been working hard
to bring Playgrounds to life.
We introduced Playgrounds
to the world Monday morning
and you saw a little bit more
about them Monday
afternoon and yesterday.
Well, today we're going to
go into a lot more depth.
We're going to start out today
with some conceptual background,
what Playgrounds actually are
and what you can use them for.
And then we'll show you examples
of how to use Playgrounds
for learning, exploration,
and visualization
of the results of your code.
We'll show you how you can
use your own custom resources
with your Playgrounds,
and how to use Playgrounds
for algorithm development
and development
of other separable
pieces of code.
We'll introduce the
XCPlayground framework
which includes some
really powerful utilities
that you can use to
enhance your Playgrounds.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that you can use to
enhance your Playgrounds.
And we'll show you how you can
develop your own Custom Quick
Looks, so that you can visualize
your own classes the same way
you visualize the classes
that come with the frameworks.
Next, we'll show
you a great demo
of how awesome Playgrounds are
for developing custom views
and in any other kind
of custom drawing
and we'll show you how you can
use your own asynchronous code
with Playgrounds.
Finally, we'll finish up
today with a little bit
about the limitations that
Playgrounds have today.
So what exactly are Playgrounds?
Playgrounds are a new type of
document introduced in Xcode 6
and they're actually a file
wrapper containing a few
useful things.
First of all is your Swift code.
The code that would be
run and the result are,
and generate results to display
automatically every time you
edit your Playground file.
Swift Playgrounds also
can contain a folder
of embedded resources which
are made available to your code
or your Playground can
reference resources elsewhere
on your system you
want to make available.
Finally, your Playground
can contain a timeline full
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Finally, your Playground
can contain a timeline full
of timeline items that
provide useful visualization
of your results beyond what
you see in the sidebar.
When you first open
a Playground,
we show the Playground Editor
with your Swift code on the left
and the results sidebar on
the right showing the result
of every expression
in your code.
Every time you edit your source,
we rerun your Playground source
from the top to the bottom
and present the new results
from that run in the sidebar.
This is the basic editor mode.
But if you go into the assistant
editor mode we'll show the
Timeline Assistant by
default which allows you
to visualize your
results in more detail.
For example, you can
display the value history
from a line in your code.
In this case, since
it's a numeric value,
we'll draw a graph of
that value over time
since it was iterated
multiple times in a loop.
If you're looking for console
output like that from Print Man,
you'll also find that in
the Timeline Assistant.
There are a couple
other useful things you,
I want to call out here.
In the lower right hand
corner, there's a time-stepper.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In the lower right hand
corner, there's a time-stepper.
And this controls how long your
Playground will continue to run
after the top of a
source is finished
if you're using live views
or indefinite execution.
And I'll explain what both of
those are a little later on.
There's also a slider which
allows you to go back in time
and view results in the
timeline from a specific point
in your Playground execution.
So here, you can see we're
viewing a numeric result
from partway through the
Playground execution.
But you'll find this is
very useful with live views
as it allows you to scrub
back through the recording
of that view and see exactly
what your animation was doing
at a specific point in time.
So that's what Playgrounds are.
Let's talk a little bit about
what you can use them for.
We think your first great use
of Playgrounds is
going to be learning.
We've introduced a brand new
language for you to learn
and we think the best way to
get started is just to open
up a Playground and
dive in and play around.
Our documentation also includes
a special interactive Playground
called the Swift Tour.
This allows you to
see documentation
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This allows you to
see documentation
and Playground Editor side
by side in the same editor.
So you can read about how
to do something and try it
out right there without
leaving the editor.
Finally, we think Playgrounds
are a fantastic way for people
to learn how to program
in the first place.
Beginners don't have to learn
how to configure a project
and target and build
and run and debug.
They can just type code
into a Playground Editor
and immediately see the results.
So if you know anyone who
wants to learn how to program,
we encourage you to suggest
trying it in a Playground.
We think Playgrounds
are also going to be
in indispensable
tool in your toolbox
for everyday code development.
If you're developing
an algorithm
or any other separable
chunk of code,
you should consider
starting it on a Playground,
working on it there until
you have it how you want it,
and then dragging that
code into your project
for use in your application.
Any sort of drawing code
you want to do is also great
in a Playground because you
can immediately see the visual
result of what your
code is doing.
And every time you
change your code,
you can immediately see how
that affects the visual result.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you can immediately see how
that affects the visual result.
Finally, processing code like
value transformers or a sequence
of image filters are
great in Playgrounds
because you can visualize
the result at every step
of the transformation process.
And when you change
something, you can see how
that change ripples
through all your results.
We think you'll find
that Playgrounds are fertile
ground for experimentation.
And in particular,
any time you're trying
to learn some new
API, you should try it
out on a Playground because you
can immediately see how it works
and what results it gives you.
You don't need a project, you
don't need to build and run.
You just open up even a
standalone Playground document,
type in your code,
and see what happens.
I'm sure all of you
have many a time gone
to create a new project from
the application template,
and gone to find
applicationDidFinishLaunching,
just to put a line of
code and to try some API.
Oh, and then you probably
have to NSLog it too
so you can see what happened.
You don't have to
do that anymore.
Now you can just open
up a Playground and try
out the API you want to try.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In fact, we'd recommend you
consider keeping a Playground
in your doc at all
times for quick access.
So anytime you want
to try something it's right
there at your fingertips.
So with all that said, let's
dive in and take a look
in an actual Playground.
To do that, I'm going to invite
my colleague Connor up on stage.
>> Thank you, Rick.
Hello everyone.
My name is Connor.
I'm an Engineer on
the Xcode Team.
And today I'll be talking to
you about how you can work
with Playgrounds as well
as some of the things
which we think Playgrounds
will be really great for.
Now, Rick has already
covered many
of the basic concepts
behind Playgrounds.
And so I think really the best
way to show you how to work
with Playgrounds
is actually just
by jumping straight into a demo.
So, let's go ahead and do that.
So here I am at the demo
machine and I'm just going
to go ahead and launch Xcode.
Now you'll notice here
that on the Welcome window
for Xcode we've added this
brand new "Get started
with a Playground" button.
It's that way we want to
make it really easy for you
to just get started with one.
So I'll just click on that.
We'll create a Playground
and I'll just give it a name
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We'll create a Playground
and I'll just give it a name
and a place to save it.
So "MyPlayground"
is fine and putting
on the desktop is fine as well.
So let's say create, and then we
have here our Playground itself.
So, you notice that
we're importing Cocoa,
so we have full access
to the Cocoa APIs.
And then we are also
creating a string
and we're assigning
the value, "Hello,
Playground" to that string.
You'll notice that in the result
sidebar we're seeing the result
of that.
So in this case we're seeing
the string, "Hello, Playground".
So OK. So that's kind
of the basic idea.
Let's try something
with numbers.
So let's say, for i in 0 to
10, let's just say, i times i.
You see there that
we execute the code
and we're getting an
indicator in the result sidebar
that we've executed
that code 10 times.
So, OK, let's try
bumping that up to 100.
We'll let it run
and we'll see there
that we immediately
get an indication
that this code has
executed 100 times.
Now, knowing that is
very useful information
but sometimes you actually
want to see the value there.
And we have support
for that as well.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And we have support
for that as well.
So OK, I'll just hover over
this result, and you'll see
that we're highlighting
the line of code
with which it is associated.
And we're also showing
this button here.
That's called the
Value History button.
And if I go ahead
and click on it,
we'll open up the assistant
editor into the timeline mode.
This is the place where you can
see results over time as well
as a place for you to
store results which you
like to see persistently.
So in this case, we're showing
the graph for i times i.
And we've seen this, you know,
this nice little curve here.
So OK, so that's kind of the
basics of using the timeline
and calculating numbers.
Let's try something a
little bit more interesting.
Let's go ahead and do
something with AppKit.
So let's first start
up by creating a color.
So you let color equals
NSColor.blueColor.
You'll see there that
we're now showing
in the result sidebar a color
swatch indicating what the color
is as well as indicators
of all of the components
which make up that color.
So I can, you know,
take this color
and let's create another
attributed string using it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and let's create another
attributed string using it.
So let's say, let attrStr
equals NSAttributedString.
And we'll pass it in the string
in an attributes dictionary.
So we'll use the
string we already have
and we'll create a dictionary.
So we'll say
NSForegroundColorAttributeName
and we'll pass it
the color we have.
And then I'll say,
NSFontAttributeName,
I'll just pass it a font.
So I'll say, NSFont,
systemFontOfSize
and then let's go to something
fairly big, so I'll just put
in 42, see what that looks like.
So, OK. So here, you notice
that we're getting a
result for this as well.
You're seeing that we're showing
the plain text representation
of this, as well as
an icon indicating
that it is an attributed string.
Now, that's great.
You know, we know that
this code is executed.
But I really want to see what
the actual value is there.
See how the attributed
string looks itself
and we support that as well.
So I can just hover over
the result and in addition
to the Value History button,
you'll see that we have
a Quick Look button.
And so if I go ahead and click
on that we'll show a Quick Look
of that value to show you
the full representation of it
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of that value to show you
the full representation of it
as it was created in
the Playground source.
So, OK, that's colors
and strings.
Let's try something with images.
Let's actually start
up by creating an
array of image names.
So I'll say, let
imageNames equals,
we'll put in an array there
and, I know it's something to do
with like NSImageNameUser
or accounts
or something in that line.
So I'm just going to create
an array with imageNames
that I think it could
be, the ImageNameUser,
NameUserAccounts,
NSImageNameUserGroup.
It's OK. We run the
code and you notice
that we now have an
array of strings.
We actually want to
see an array of images
and that's very easy to do.
I can just say something like,
let images equals
imageNames.map.
I'll pass it a trailing closure
to just say, NSImage named,
pass it the positional
argument $0.
And you'll notice there that
we're now seeing that this line
of code executed 4 times.
And so, basically
we can see that,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so, basically
we can see that,
you know, OK, that makes sense.
We're executing this
line of code 3 times
for the trailing closure itself.
Then we're executing it once
for the assignment to images.
Actually, I only want to
see the images array itself
and we have a nice little trick
for doing that in a Playground.
You just go ahead and put
the thing that you want
to see on a line by itself.
So there you see, you know,
we've put images there,
we rerun the code, and we're
seeing the images array.
I can Quick Look that and
I can see, "Oh, you know,
here's the image that
I'm looking for."
And so, I'll just get
that image and say,
let image equals images at 0.
We'll rerun it.
I'll Quick Look to make sure
it's OK and in fact, yeah,
that's the one that
I'm looking for.
Let's go ahead and put
this into an image view.
So I'll say, let
imageView equal NSImageView.
We'll pass our self a
frame, so let's say NSRect.
We'll say 0 for the origin
because we don't
really care about that.
Then we'll also say 512
by 512 for the size.
Now I'm going to go ahead
and put this ImageView
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now I'm going to go ahead
and put this ImageView
on its own line as well.
So I can show this
result in the timeline.
And this is a neat little
way of building something up.
You take the, you start
creating the object
and then you put another line
where we show it as a result.
Anyway, I can add some
code in between there
to see how it builds
up over time.
So you see here that
we're starting
out with just this empty
imageView, you know,
we're not seeing any
interesting there.
So let's go ahead add our
image to the imageView.
So let's say, imageView.image
equals image.
And we'll re-execute and
we'll see here now that we're
in fact showing the image there
but it's not filling
the full imageView.
It's not doing what we expect.
That's because we haven't set up
the image scaling appropriately.
So we'll set that as well.
Say imageScaling equals
ImageScaleProportionally
UpOrDown. And we'll
re-execute and now you'll see
that we're seeing the image
at full size in the imageView.
We're seeing what we expect.
And it's OK.
That's how you can work
with system resources.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
That's how you can work
with system resources.
But I'm sure you have many
resources of your own that you'd
like to use in Playgrounds
as well.
And we support that too.
So I'm just going to
go ahead and I'm going
to show the final inspector.
It will slide in on the
right hand of my Playground.
And you'll notice
here that we're,
we have this new section
called Playground Settings
which is shown whenever you're
viewing a Playground document.
You can select the platform
against which the
Playground should execute.
And, you know, OS X is
what we're doing right now.
But we also support iOS.
And you can select a
path for resources.
This defaults to none
but you can select one
if you have resources
that you're interested in.
In this case, I'm just going to
say I have a folder of resources
on my desktop so I'm
just going to say,
let's use the Absolute
Path option.
I can then go ahead
and choose that.
So let's say here's my resources
folder, I'll choose that.
And then once I made that choice
I'm actually going to go ahead
and hide the Utilities area.
And to access the images
themselves, I just use,
you know, NSBundle API, you
know, the resources show
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you know, NSBundle API, you
know, the resources show
up as resources for
the main bundle.
So I can say something like "let
myImage equals NSImage, named".
I have an image in
here that's just called
"Xcode" so let's grab that.
We'll re-execute
and you'll notice
that now we're getting
the image result here.
And click, click to confirm
that it's what I think it is.
And in fact, it is, we're
seeing the Xcode icon there.
And now I'm just going to have
that imageView show
the Xcode icon instead.
So, I'll say, "imageView.image
equals myImage".
We'll re-execute and now
you're seeing this new result,
let's add it to the
timeline as well.
So you can see here that
we have what we expected.
The Xcode icon is showing
up in our imageView.
You'll probably also notice
that we're still seeing
the older version here
with the user icon
in the imageView.
And that's because Playgrounds
actually capture results
on every single line
of execution.
So you can do these
kinds of comparisons.
So like for instance, you know,
let's look at the imageView
when we first create it.
And it's empty.
Then I added the
user icon to there.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Then I added the
user icon to there.
And so, we see that
earlier version that we saw
where it's small in the center.
Then I set the image
scaling appropriately
and it's now filling
full image view.
Finally, I updated it to
use myImage and we're seeing
that it's showing
the Xcode icon.
And that's great, so that you
don't have, you know, go back
and see what happened
at a particular point.
We're capturing the data for
you as your Playground executes.
So I think that about covers
the basics, so let's go back
to slides and talk a little
bit more about Playgrounds.
So one of the key ideas
that you saw there is
that Playgrounds will
automatically execute.
You just type in some code
and you'll see the results
in a sidebar on the right.
Additionally, you saw that
we can add a value history
to the timeline.
So here we have a line of
code which executed 100 times.
And if I hover over that result,
you'll see this Value
History button.
If I click it, we'll switch
into the assistant editor
and we'll show that as
a history of that value.
Additionally, many values in
the Playground have Quick Looks.
All right.
So in this case we have
an attributed string.
We don't see the full
representation of the sidebar,
just kind of the
plain text of it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
just kind of the
plain text of it.
But if I click on the
Quick Look button,
we'll see the attributed
string as it was created
in the Playground source.
We support many different types
for Quick Looks in
the Playground.
We support colors, strings --
both plain text and attributed.
We can show images, views,
in this case we'll capture
a snapshot of the view
at that point in time.
We can show arrays
and dictionaries
as we'll show a structured
version of the array
or dictionary, ah,
like you might see
in the variables
view on the debugger.
We can show points,
rects, and sizes.
We'll kind of create a graphical
representation of those.
We can show Bézier paths, so
both NSBezierPath on the Mac
and UIBezierPath on iOS.
We can show URLs, for this we'll
take the plain text of the URL
and show it in the sidebar.
But if you Quick Look, it
will show you a web view
with the contents of that URL.
And finally, for types
if we don't have a native
Quick Look representation,
we can usually get a
structured view of it, again,
like you would see in the
variables view in the debugger.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So here I have an
object of a class
that I created in
the Playground.
And it is, it has a
couple of properties,
a foo property and
a bar property.
And you're seeing the
values of those at that line
of code when it executed.
In this demo, I also showed
you how you can use your own
resources with Playgrounds.
And this is actually
fairly easy.
So you just go ahead and
show the file inspector.
You select a location
for Playground resources.
And for this we have
three options.
We've got an Absolute Path
option which basically says,
"OK, I've got this folder
of resources somewhere
on my computer and
I'd like to show it
and use it with the Playground."
We have a Relative to
Playground path option.
And this is really great
if you're checking your
Playground into SCM.
Because you can say, "Oh, you
know, here's this Playground
and here's this folder of
resources that's next to it,
I can set this up and then when
you use other people to check
out your repository, then it
will automatically be able
to use the Playground
with its resources."
Finally, we support an
Inside Playground option.
And this is great
if you're sharing
in ways other than via SCM.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in ways other than via SCM.
Because you can just say, "I
want to store my resources
in my Playground" and you can
email that out to other people
and see, when they open
it, they'll be able
to see those resources
immediately.
Once you have made
the selection,
to access these resources
in your Playground source,
you just use things like,
NSBundle.pathForResource
ofType and NSImage named.
The resources just show
up as the resources
for the main bundle during
Playground execution.
So, now that we have the
basics out of the way,
I think I'd like to start
talking to you about some
of the use cases for
which Playgrounds would be
really great.
And the first of these
is Experimentation.
I'm sure that all of you
out there have a folder
on your computer which
looks something like this.
It's just a bunch of
Xcode projects created
from the template that are,
you know, maybe 1 or 2 changes
to see how something works
or to test out an idea.
It's actually isn't
that easy of a process.
You know, you have to
do many different --
you have to first choose the
right project template then find
the right file in that project
to edit which may be easy
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the right file in that project
to edit which may be easy
or maybe not depending on
which template you chose.
You'd have to do what you're
trying to do in the first place,
and that's write some code.
Once you've written
something, you then have
to build your project.
You then run whatever you built.
And for iOS that may
involve deploying
to a simulator or to a device.
And if you didn't get it right
the first time, you'd then have
to redo this, stop in
the debugger and step
through your code to figure out
where things are going wrong.
We think Playgrounds can
handle this a whole lot better.
That's because there's
really only 2 steps.
You would just, say, get started
with a Playground
and write your code.
Once you start writing
your code,
we'll automatically execute it
for you and show you the results
in the sidebar so you can see
where things are going wrong.
So now, I think I'd
like to show you a demo
of what this looks like.
So let's go back to
the demo machine.
So here I am.
I'm going to go ahead and
just launch Xcode again.
And this time I'm going to
create an iOS-based Playground.
So I'll say, File, New File,
and I'll say, iOS Playground.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And I want to actually test
out how the UITableViewCell
style API works.
So, I'm just going to call
and create this Playground
and call it TestTableViewCell.
Save it to the desktop, and OK.
So, here we have
our iOS Playground.
It's, you know, importing UIKit,
but otherwise, it's the same,
we're just creating a string
and assigning it to a variable.
So, if I want to use a
UITableViewCell style,
I need a UITableViewCell.
And the best way to show
that is with a UITableView.
In order to get those cells
into my UITableView,
I need a data source.
So, let's just go ahead and
implement a data source.
So I'll say "class DataSource".
We'll inherit from
NSObject and we'll conform
to the UITableViewDataSource
protocol.
Notice now that we're getting
an issue here and that's
because the DataSource we've
created does not actually
conform to
UITableViewDataSource.
And, you know, that's expected.
We haven't actually
implemented any methods yet.
So, I'm actually going to
jump to the declaration
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, I'm actually going to
jump to the declaration
of UITableViewDataSource by
command-option-clicking on it.
We see that we then open
the assistant editor.
And instead of showing
you UITableView.h,
we're going to show you a
Swift version of that header.
So, in this case, we're seeing,
you know, here's our protocol.
We're seeing that we need to
implement these two methods.
And so, OK, I'm just going to
take this one, this first one
to tell the TableView the
number of rows per section.
I'm going to copy
and paste it in here.
And then I'm just going to start
things out, return 1 from this.
So, OK. So that's
the number of rows.
Let's also provide the cell.
And OK, let's just go ahead
and create our UITableViewCell.
Let's say let cell
equals UITableViewCell.
I need to fix this typo.
Here, we'll say the style, we'll
just say the default style.
And then for the
reuseIdentifier,
we aren't actually going
to be reusing these cells
so we can just pass
nil for this parameter.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so we can just pass
nil for this parameter.
And OK, so there
we have our cell.
Let's go ahead and configure it.
So, I can say something like
cell.textLabel.text equals Text.
OK. So that's the text label.
We'll see what that looks like.
UITableViewCell may also
have a detail text label.
But that's not guaranteed
to be the case.
So I'm going to explicitly
handle the fact
that it's an optional.
So, I can say something like
"if let detailTextLabel
equals cell.DetailTextLabel".
And so, if the code inside
of this "if" executes,
then we'll know that we
have a detailTextLabel.
So, I can say something like,
detailTextLabel.text
equals Detail Text,
and we know that this is safe.
We're not going to accidentally
try to assign a property to nil.
So now that we've configured
our UITableViewCell,
I can just go ahead
and return that.
You can see now that we
no longer have an issue
in our Playground.
But we're also not getting
any results in the sidebar.
That's because we haven't
actually instantiated our
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
That's because we haven't
actually instantiated our
data source.
So, I'll just say something like
DataSource equals DataSource
and then I can, you know,
I'll just create a TableView
and tell it to use
our DataSource.
So, let tableView
equals UITableView.
We'll pass it a frame
so, CGRect.
Again, we don't care
about the origin.
I'll pass 320 for the width,
and for the height we just
need enough to be able
to show all the cells
we care about.
So, I'll just say
something like 240.
Finally, we'll pass
a style of Plain.
We'll then tell the tableView
to use our DataSource.
And then, we will tell the
tableView to reload data.
Let that Playground execute.
And once it's finished
executing, we'll be able
to see the tableView
we've created.
So, I'm going to just go ahead
and add this to the timeline.
We can see here that we've
created our tableView, you know,
we're seeing the
cell that we want,
with the text that we want.
So, OK. So that, you know,
gets us up and running.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, OK. So that, you know,
gets us up and running.
But actually I want
to see the styles
for all the styles that we have.
So, I'm going to jump
back to the declaration
of UITableViewCell style.
And you can see here
that there are 4 options.
So I'm going to change this
1 to a 4, so if 4 rows.
Instead of always
passing the default style,
I'm going to conditionalize
it based on the row
that we're currently at.
So, I'll say let row
equals IndexPath.row.
And I'll say something
like let style equals
UITableViewCellStyle.fromRaw.
I'll pass the row.
This fromRaw will convert the
UITable, the raw row integer
into a UITableViewCell
style optional.
And we confirm that by using
quick help and we can say that,
"Oh, yes in fact, this
style is an optional
UITableViewCell style."
If we were to pass
this directly here,
we would get an error
as you can see here.
We need to explicitly handle
the fact that this could be nil.
You know, the UITableViewCell
initializer doesn't expect that.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You know, the UITableViewCell
initializer doesn't expect that.
So, let's go ahead
and check that.
So we'll say, if we have
a style, let's unwrap it,
otherwise you just
use the default style.
It's OK. Now that
we've handled that,
let the Playground
re-execute and let's jump back
to the timeline using
the jump bar.
And once it's re-executed,
we'll notice here
that we're now seeing all the
different UITableViewCell styles
in our tableView.
And so now, I have a Playground
which I can, you know,
share with my co-workers or
just keep it as a reference
for myself to see what
each UITableViewCell style
looks like.
Let's go back to slides now.
So that showed you how
great Playgrounds are
for experimentation.
You just get started
with an idea,
write some code, and
see how it works.
And now I'd like to invite
Rick back on stage to talk
about another great idea
we have for Playgrounds
and that's Algorithm
Development.
Rick?
>> Thanks, Connor.
Developing algorithms and any
other separable pieces of code
in a Playground is
a great way to go.
And so to show you that, I'm
going to dive right into a demo.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so to show you that, I'm
going to dive right into a demo.
So what we're going to do today
is implement insertion sort,
a fairly straightforward sort.
We're going to create a brand
new Playground to do that.
So I'll just say get
started with a Playground,
and we'll call the
Playground InsertionSort
and save it on the desktop.
If you're not familiar
with insertion sort,
imagine that you have a hand of
cards and you want to put them
in order with the
lowest values in the left
and the highest values
on the right.
One way you might do that
is, start with the second
to leftmost card and compare
its value to the leftmost card.
If it's less, you'd
swap the position
of the two cards in your hand.
You'd then look at the third
to leftmost card and compare it
to the second to leftmost.
If it's less, you'd swap it,
compare it to the leftmost card,
swap it if needed, and go
on doing this for every card
in your hand until every
card had reached the correct,
sorted position.
When you're done, your
hand will be in order.
So, let's implement
that in a Playground.
To start with, we
need some random data
that we're going to sort.
So, I'm going to go
ahead and I'm going
to declare an array of data.
I'm going to use var
because this needs
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm going to use var
because this needs
to be a mutable array, so I
can add to it and sort it.
And we'll just make an empty
array of ints to start with.
And I could say for
i in 0 through 20,
because maybe I want
20 data points.
I can say data.append
to add a new element.
And let's use the
arc4random function
to generate a random number.
That doesn't return a
Swift Int, so we're going
to cast it explicitly
to a Swift Int.
And we'll modulus it by 100 to
get a number between 0 and 99.
So if I look at data here,
you can see I have a
result here on the right.
Here's an array of what look
like pretty random numbers.
You'll also notice if I edit
the Playground source again it
reruns and I get a different
array of random numbers.
Ah, OK, so that's great.
Well, it's nice to be able
to generate random data
but I probably don't
want it to change
on me every time I edit
the Playground source
because that might make it
hard to develop my algorithm.
So, let's grab this random
data and use it every time.
To do that, I'm going to
click over the result sidebar
and use command-A to select
this data, command-C to copy it,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and use command-A to select
this data, command-C to copy it,
and then I'm just going to paste
this in here as array literal.
And now I can work off the
same random data every time.
OK. So, let's start
implementing our algorithm.
The first thing we
need is a function
to swap two points
of data in our array.
There actually is a
built-in function called swap
for this already.
But for the sake of argument,
we'll implement it ourselves.
So, I'm going to say func.
I'll call mine exchange.
You know, we're going to make
this a generic because, well,
we have an array of ints.
Our insertion sort should
be able to work on any type.
So, any type at least as
long as it's comparable.
One element can be
compared as greater
than or less than another.
So, we'll mostly work on
comparable types here,
the exchange function
can work on any type
because we just are
swapping types.
So this is an exchange
using a type D.
And it's going to take an
array of T and two indexes
which we're going to
exchange in the array.
So, the simplest way to exchange
these objects is to assign one
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, the simplest way to exchange
these objects is to assign one
to a temporary variable,
assign the second to the first,
and assign the temporary
variable to the second.
So, we can say let
temp equals data of i.
Data of i equals data of j.
And data of j equals temp.
OK. I think we've
implemented this correctly
but let's try it and find out.
I can say exchange,
pass my data array
and we'll say exchange the 0th
element with the second element.
And then we'll take a look
at our array when we're done.
So, before, element 0 was
12, and element 2 was 15,
now element 0 is 15
and element 2 is 12.
So, it looks like
exchange works properly.
OK. The next thing we need is
a function to, given an index,
look at the data
point of that index,
compare it to the data point
to its left; if it's less,
exchange them and keep
comparing and exchanging
until it reaches the correct
position in the array.
So, let's call this
function swapLeft.
Again, it's a generic
but this time we need
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Again, it's a generic
but this time we need
to actually do a comparison.
So, we're going to say our type
D is comparable and we're going
to pass an array of T and an
index of the data point we want
to start swapping left.
OK. So, let's implement
this, we're going to start
with our index and go
back to position 1,
not 0 because there's nothing
to the left of 0 to swap.
So, I'm going to say
for i in, and, you know,
I could do a range
from 1 to index
but what I really
want is index to 1.
So I'm going to reverse
the range with reverse 1.
3 dots makes it a
fully closed range
which means it will go
all the way to index.
So, since I'm reversing this, it
goes from index and ends at 1.
And for each of these data
points, I'm just going to say
if data of i is less
than data of i minus 1,
exchange data i and i minus 1.
OK. If it's not less
than data of i minus 1,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
OK. If it's not less
than data of i minus 1,
it must have reached the
correct sort of position
in the array, so
we can stop there.
So, let's say else break.
OK. Let's try this function out.
I'm going to go ahead and
say swapLeft, pass data,
and let's pass element
1, 2, 3, 4, 5, 6.
Let's pass element 6 left.
Oops! And look at our data.
And you can see the 0
has moved all the way
from the 6th position to
the beginning of the array
and everything's been
moved to the right.
So it looks like this
function is working great too.
OK. The last thing we need is
to actually implement the sort,
so this should be pretty simple.
We'll call our function isort,
works again on type
T that is comparable.
And we can just pass
an array of T
and it will sort
the whole array.
To do this, I'm just going to
say for i in 1 (we're starting
at 1 because there's nothing
to the left of 0 to sort to)
to data.count, swapLeft,
data and i.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to data.count, swapLeft,
data and i.
So, let's try it
out, isort data.
And we'll look our data
array when we're done.
And you can see it did a whole
bunch of assignments up here.
And now here's our
final array and it looks
like this is in sorted order.
So, we've correctly
implemented insertion sort.
So, this is great for a simple
algorithm like insertion sort.
That wasn't too hard.
But you know if I was doing
something more complicated,
it might be nice to
have more visibility
into exactly what's
going on here.
So, let's look at how we
might visualize our results
in more detail.
Well to start out with, let's
draw a graph of the results
of the data at the beginning.
To do that, I'm just going to
say for x in data (to iterate
through every data point)
and just print out x.
And so, you'll see there
are 20 data points here.
So this line executed 20 times.
And if I click on the
Value History button,
I get a nice graph here showing
my data at the beginning and,
boy, that does look random.
OK. So, now I want
to try to print
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
OK. So, now I want
to try to print
out another graph every
time swapLeft is called,
so I can see what's
happening to the graph
over iterations of swapLeft.
And I could put this
"for" statement in the end
of swapLeft again and
show the Value History.
But again, in Value History
Timeline item for given,
a line is going to show all
the data from that line.
So, each time swapLeft
is called,
its data would be
appended to the same graph.
That's not what I want.
I want a new graph,
every time it's called.
So to do that, we're going to
need a new tool in our toolbox.
I'm going to go back to
slides and show you that.
With Playgrounds, we're
shipping a new framework called
XCPlayground and it contains
some very useful utilities
for enhancing your Playgrounds.
Right now, we have API for
manually capturing values
to display in timeline items,
showing your views live
and extending execution
for asynchronous code.
Right now, we're
going to use the API
for manually capturing values.
That API is called
XCPCaptureValue.
It's a function that takes an
identifier, which is a string,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's a function that takes an
identifier, which is a string,
and your value, which
is of any type.
When you pass it -- your value
-- it will take that value
and put it in a timeline
item for you.
So, the identifier that you pass
it identifies what timeline item
you want that value to go to.
If you call this function
on different lines
but pass the same identifier,
the values from those
different lines will go
to the same timeline item.
Conversely, and what we want
here, if you have one line
that calls XCPCaptureValue
but it's called multiple times
with different identifiers
and it passes those
different identifiers,
that one line can generate
multiple different timeline
items (or grabs, in our case).
That identifier is also shown
as the name of the timeline item
so you can easily see
what data is what.
The value pass can be
anything, because it's a generic
but it helps if it's a type
of value that we know how
to Quick Look appropriately.
So, let's go back
and give this a shot.
So to start out with, I
need to import XCPlayground
to make this API available
and I'm going to go ahead
and define a new function.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and define a new function.
I'll call it visualize
and it's a generic.
And it will take an array of
type T and I'm going to use this
"for" loop in it, so
I'll just indent that
and close the function.
But instead of just
printing out x, what we want
to do is capture that value.
So, I'll call XCPCaptureValue.
I need an identifier, so
let's add one to our function.
So, identifier is a
string and we could pass
that identifier,
and our value is x.
OK. So let's try this function
out and visualize the data
at the start of our sort
and we'll label it Start
as the identifier just
so we know what's what.
And here you can see it ran and
here's our data at the start.
So that's a good start.
So now, we're going to go
ahead and visualize our data
after every iteration
of swapLeft.
So, I can call visualize,
I'll pass data as it is
after this iteration
of swapLeft.
And for our identifier, let's
label it after the iteration,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And for our identifier, let's
label it after the iteration,
the number of times
that swapLeft is called,
which is the index parameter.
And so, I'm going
to let this run now.
And you can see that it's
generated multiple graphs
labeled after the
iteration that we're on.
So, now we can just
scroll through here
and see what's happening to our
data over time as swapLeft runs
and the sort completes.
You can see it looks like our
data is getting sorted piece
by piece.
And so, at the end, we
have a nicely-sorted array.
So there, we can easily
visualize exactly what's going
on with our algorithm.
We think you'll find
this very, very useful.
OK. Let's move on
to another example.
I've got a heap Playground
I made here earlier.
And it's got this
HeapGrapher class at the top
which I'll explain in a moment.
But the meat of this class
is my heap class which,
if you're not familiar with
a heap, a heap is a type
of balanced binary
tree where the value
of every node is
greater than or equal
to the value of its children.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Heaps are often used to
implement priority queues,
because it's very efficient
to remove the highest
priority item, that's the top
of the tree, and it's also
efficient to insert new items
into the correct position of
the tree for their priority.
We're implementing our heap
with an underlying array
to represent the tree.
And in our array, the tree
noted index i has children
at indexes i times 2
and i times 2 plus 1.
So you can see down here
at the bottom we've
got some random data
that we seeded ourselves with.
And we've created a new
heap with that data.
And we "heapified the heap,"
which is to say, put that data
into correctly heap-sorted
order.
On the right, in
the results sidebar,
you can see our default
treatment
of this custom class is to
show the name of the class
and show its properties.
In this case, it has
one property which is
that heap array and here it
is before it's been heapified,
when it's not a correct heap.
And here it is after
it's been heapified,
when it's purportedly
a correct heap.
But you know, it's really
hard to tell looking
at this array whether
that's a correct heap.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
at this array whether
that's a correct heap.
This array represents
a tree and, you know,
not so good at visualizing,
"Hh, well, here's I,
and here's i times 2,
and yeah, that's less..."
Wouldn't it be much better if
I could just visualize this
as a tree everywhere
my heap is referenced
to my Playground source?
So let's see how to do that.
In order to visualize
my own custom class,
we're going to implement
Custom Quick Look Support
for this class.
Our Custom Quick Look Support
allows you to add Quick Looks
for subclasses of
NSObject only (right now).
And to do it, you implement
the debugQuickLookObject method
which takes no parameters
and returns any object
as an optional.
And you're going to return
the value that you want
to represent your
object as its Quick Look.
So, right now, that
value (the values
that we support here) are
colors, strings (both plain
and attributed),
images, and Bézier paths.
So, for your Custom Quick Looks
you can use any of these types.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, for your Custom Quick Looks
you can use any of these types.
So, let's try it out.
OK. So I mentioned before I
had a little HeapGrapher class
that I wrote.
That's a little class that knows
how to take an array and draw it
as a tree, so we're
going to use that.
We'll implement our
debugQuickLookObject method.
It takes any, or returns
any object as an optional
and we're just going to create
one of our HeapGraphers.
And this HeapGrapher knows
how to generate an NSImage
which is one of the Custom Quick
Look types, supported types.
So, we're just going to
return the image it generates
with g.graphHeap and
pass self.heaparray.
And now, when this runs, instead
of showing the default
representation for our class,
it shows our custom Quick
Look representation,
which is an image.
And so when I click
the Quick Look button,
you can see here it's
drawing my heap as a tree.
This is before it's been
heapified when you can see,
for example, 78 is less than 89.
So this is not a correct heap.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But if I Quick Look it
after it's been heapified,
I can now go, oh great, 91
is greater than 86 and 89,
86 is greater than 84 and
79, and so on and so forth,
and I can really
easily visually verify
that this is a correct heap.
So that's how you can Quick Look
your own classes in Playgrounds
and we think you'll
find that very useful.
All right.
Next, we'd like to move on to
showing you how great it is
to do Custom View Development
and other drawing
development in Playground.
And to do that, I'm going
to hand it over to Connor.
>> Thank you, Rick.
Another great use case we
think Playgrounds will be used
for is Custom View Development.
And that's because you can
just start writing some code
and see the actual view
as it's being drawn
and as you're starting to
build up your drawing code.
So for this I have a goal.
I want to take this
Playground icon
and add some animation to it.
The icon that we
have is really great.
It conveys the playfulness
of Playgrounds.
But unlike Playgrounds
themselves, it's static.
There's nothing dynamic
about it.
And so, I'm going to try
to add animation to this.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so, I'm going to try
to add animation to this.
And what better way
to do it than when
in a Playground itself?
So, let's jump over to the demo.
So OK, here I'm going to go
ahead and open up a Playground
that I've already started.
So, OK. So here we've
got a Playground.
We've got our subclass of NSView
called PlaygroundIconView.
It has a few layers.
It's got these three instance,
er, these three instance methods
which actually do the
setup of those layers.
You see that they're
unimplemented right now
and we'll come back
to that in a moment.
I also have an extension of
NSColor which defines a couple
of colors for the
Playground icon itself.
I then have a helper function
to convert an NSBezierPath
to a CGPath for use
with CAShapeLayer.
Finally, I just go ahead
and create an instance
of my PlaygroundIconView.
And then, I put it
on a separate line
so I can add some stuff later.
Let's go ahead and show
that in the timeline.
So, OK. So you'll see now
that we've just got
ourselves an empty view here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that we've just got
ourselves an empty view here.
So yes, we have an
empty view here.
We actually just
now need to go ahead
and implement these
setup functions.
So let's go ahead and do that.
So we'll start out
by creating the path
for the background layer.
So you can see here we're
creating NSBezierPath
and we can Quick Look it to
make sure it looks right.
And in fact, yeah,
that looks more or less
like the Playground icon.
So let's tell, let's
setup our layer.
So OK, now we're
setting up the layer.
You can see here in the timeline
that we're now drawing the
layer where, you know...
We have the background, we've
got the little border there,
and so, OK, we've got
our background set up.
Let's also do the seesaw base
and we'll do the same thing.
We'll create a path for that.
And we'll let it execute
and we'll see here,
let's Quick Look, make sure...
Yeah, that looks more or
less like the little base
that we have for the
play- ...for the seesaw.
So let's set up the
layer itself as well.
And there, we just
make that change
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And there, we just
make that change
and immediately get the feedback
of seeing what that looks
like when drawn in our view.
Let's also do the seesaw layer.
I've got some code here
to set that up as well.
You see here that we're just,
you know, have a closure
which will create the
child layer itself.
We then create a couple
of layers for the children
on each side of the seesaw, and
then we set up the bench itself
and then add those layers
to our seesaw layer.
So, OK. So now we've
got ourselves something
that looks kind of like
the Playground icon.
But like the icon itself,
it's not animating.
So let's go ahead and
add support for animation
to our PlaygroundIconView.
I have a snippet
for that as well.
And so, let's walk
through what this is doing.
I define a constant for the
maximum angle of the seesaw.
I've, you know, worked
through this and I think pi
over 12 is about right.
I also have a property for the
current angle of the seesaw
after any pending
animation is finished.
And then have a property
which determines whether
or not it should be animating.
It starts out as false
but we have this code here
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It starts out as false
but we have this code here
which executes whenever
this is set to say, "Well,
if the animation state
has changed and we're told
to animate, then just
start animating depending
on the current angle
of the seesaw."
I then have this helper method
for actually performing
the animation itself.
So we just, you know, go ahead
and create a CABasicAnimation,
set a couple of values,
set our timing function
to match what a seesaw
would actually look like.
Set the duration to what
was passed in which defaults
to 1-1/2 seconds, but can
be customized depending
on the angle of the seesaw.
We then add the animation
to our seesaw layer.
We set the underlying transform
property of that seesaw layer,
so that once the animation
completes it looks correct.
And then we update our
current seesaw angle
property accordingly.
Finally, we have, uh, we
implement the "animationDidStop,
finished" delegate callback.
Or basically say
that if we finished
and we're still supposed
to still be animating,
then just go ahead and
animate to the opposite angle
of what we currently are at.
So, OK. Let's go ahead and tell
this view to start animating.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, OK. Let's go ahead and tell
this view to start animating.
So we'll do that and you'll
notice that after it reruns,
we seeing the view update
it's look, you know,
so we see that it
tilted over to the side.
We're not seeing the
animation itself.
And for that, we're
going to need some help
from the XCPlayground framework.
So, let's switch back the slides
to see what that
could look like.
So the second piece
of functionality
which the XCPlayground framework
provides is the ability
to show live views
in the timeline.
And you do that by calling
this XCPShowView function.
It takes an identifier and the
view that you want to show.
After calling it, we'll show the
view live while the Playground
executes and then
we'll record frames
as the Playground executes
so you can play them back
once execution finishes.
The identifier you pass to this
function must be unique inside
of the Playground.
That's because this
is how we refer
to the live view
internally in Xcode.
And it is also what
we'd show as the title
for the live view
in the timeline.
The view pass must also
not have a superview.
This is because we will add
it to our own view hierarchy
and it would generally not
produce the results you're
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and it would generally not
produce the results you're
looking for.
So with this in our toolbox,
let's jump back to the demo
and see how it's used.
So I'm going to go
ahead and just go ahead
and import XCPlayground.
And then down here, instead
of just having this view item,
I'm going to remove
that from the timeline.
I'm going to say
something like XCPShowView
and pass an identifier.
It can be anything as
long as it's unique.
So I'll say Playground
Icon View.
And then I'll pass the
view that we've created.
So, we'll just let
that re-execute.
And you see there
that in the timeline,
we're showing the view
live as it's animating.
You-all also probably noticed
this little timeout field
down here.
And that lets us specify
the amount of time
which we'll let the
Playground continue executing
after we reach the end of
execution of the top of a code.
Now, it defaults to 30 seconds
but I'm going to adjust this
down since I know my
animation only takes
about a second and a half.
So I'll do 10 seconds to
get a few times around.
After we edit that,
we'll rerun it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
After we edit that,
we'll rerun it.
And so that's great, you
know, we see it running there.
And I'd like to show how you
can integrate XCPShowView
with the XCPCaptureValue
API we mentioned earlier.
And so, what I'm going to do,
I'm going to capture the angle
of the seesaw, or
of the left edge
of the seesaw as
we're animating.
So here, I'm just going
to say XCPCaptureValue.
I'll pass Left Seesaw
Position and I'll just pass 0
because we know at
this point that it's,
you know, it's flat on there.
Then you can take this and
I'm going to put it in our
"animationDidStop,
finished" callback.
Now I'm going to just pass the
negative currentSeesawAngle.
That's just because that's
what we need to do in order
to get the left position
of the seesaw.
That is how the angle works
out for the transform.
So you see here that
as we're executing,
we're getting the graph kind
of building up over time.
And then once execution
finishes,
the graph will snap
back into place and kind
of show you the best view of
the data that it collected.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's OK. You probably
also noticed this slider
became active.
And so, I can just go
ahead and take that
and drag it through here.
And you'll notice that we're
updating the graph at the bottom
but we're also showing you
the animation, you know,
as it went through in time.
So this is, you know, a
fairly basic animation
and it's doing what we
expected but, you know,
if you had something
more complex and you want
to just kind of take a look
at just a small portion
of your animation, you
could do that as well.
And I can also do
something like, you know,
click on one of these points.
So I can click there.
We can see it, you know, that
the two things are in sync.
I click there.
It updates the point.
I can use the arrow keys to
go through the graph's points
and see that, OK,
yeah, you know,
we're doing what
we expect it to do.
And so, that's how you can
show live views in the timeline
with the XCPlayground framework.
Let's go back to the slides now.
Now, I'd like to talk to you
about how you can
use asynchronous code
in your Playgrounds.
You got a little taste of
this in the demo before.
But I'd like to go into a
little bit more detail now.
The third piece of functionality
which the XCPlayground framework
provides is the ability
to extend execution.
By default, execution terminates
once all top-level code
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
By default, execution terminates
once all top-level code
has executed.
XCPlayground, though,
provides API
for extending execution
indefinitely.
That's this
XCPSetExecutionShould
ContinueIndefinitely function.
You should know that this is
actually not quite indefinite.
The execution time is controlled
by the timeline's timeout
which defaults to 30 seconds.
Additionally, execution
will be terminated
if you edit the Playground
while it's running.
This is so that we can show
you up to date results rather
than let, leaving you a
stale results while we wait
for an earlier execution
to finish.
Additionally, as you saw
on the last demo, you know,
we didn't actually
call this function,
but we saw that execution
continued
after we reached the
end of top-level code.
That's because XCPShowView
implicitly
calls XCPSetExecutionShould
ContinueIndefinitely.
You should just think
about this as if nothing
in the Playground
source has told Xcode
that the Playground
used to stay alive,
then the Playground will stop
executing once we reach the end
of top-level code.
So now, I'd like to show you
a quick demo of what it's
like to use asynchronous
code in Playgrounds.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So here I am back here
and I have a Playground
which uses asynchronous code.
We create, uh, we have
our session delegate
which is an
NSURLSessionDelegate.
It has a few callbacks.
And then we also just, you know,
create an instance
of our delegate.
We created an NSURLSession.
And then create a data task
to download the contents
of the Apple home page.
We then tell the
data task to resume.
And you noticed that, you know,
the Playground itself
has executed
but we're not receiving
any results up here.
And if I open up the
assistant editor, you'll notice
that we haven't received any
console output even though they
were clearly logging here that
we've received some bytes.
And this is because nothing
in the Playground has
told the Playground
that it should continue
executing.
So we call task.resume, we
resume the task and then as soon
as that finishes, we hit
the end of top-level code
and the Playground
just stops executing.
Let's go ahead and say
import XCPlayground.
And then we can say
XCPSetExecution
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And then we can say
XCPSetExecution
ShouldContinue,
XCPSetExecutionShould
ContinueIndefinitely.
This takes a Bool but
that defaults to true,
so you typically don't need
to pass anything there.
And I won't do that here.
You'll now notice that, you
know, we were receiving results
from here and we're also
seeing the console output
that we expect in the timeline.
So OK, that's how you
use asynchronous code
in Playgrounds.
Let's go back to slides now.
There are a few alternatives
but we really think
that you should typically
use XCPSetExecutionShould
ContinueIndefinitely
when you're trying
to use asynchronous
code in Playgrounds.
If that won't work
for you though,
you can use other
methods for waiting
for asynchronous
operations to finish.
Basically, you just need to make
sure you don't reach the end
of top-level code before
your operation completes.
Before we leave today, I'd like
to talk to you a little bit
about some of the limitations
we have with Playgrounds.
First off, you should
not use performance, uh,
Playgrounds for any
performance testing.
That's because the
logging of results
in the Playground will
generally dominate the runtime,
not your actual code.
This means that the performance
will be dependent on the number
of lines of code executed,
not the actual performance
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of lines of code executed,
not the actual performance
of whatever it is
you are developing.
And that's not necessarily
what you'd expect.
Instead we'd suggest that
you use the XCTest framework
to create performance
tests in a test bundle
where you can get
more accurate results.
We have a session later this
week called Testing in Xcode 6
which will go into
this in more detail.
There are few more
limitations with Playgrounds.
Playgrounds cannot
be used for things
which require user interaction.
So we have great support
for showing live views
but you can only see them,
you can't touch them.
We also do not support using
Playgrounds for anything
which require custom
entitlements.
For iOS Playgrounds, we
only support executing
against the simulator.
So anything which requires a
device will not be supported
with Playgrounds.
And finally, we do not
support using your own app
or framework code in a
Playground unless it's something
that you can just copy and paste
into the Playground source.
Basically, you can only use
things in the standard library,
in the SDK, or that's in the
Playground source itself.
You can get around some of these
limitations by using the REPL.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You can get around some of these
limitations by using the REPL.
The REPL is the command
line interface to Swift
and it works this way because
the REPL can actually execute
in your own process.
You just stop at a breakpoint,
and then at the LLDB prompt,
you execute the REPL command
and you'll just be dropped
down right into the Swift REPL.
Playgrounds though provide a
richer experience than the REPL.
And that's because we will
automatically execute your code
from a known state.
That means, you know, you make a
single edit to a line and then,
you know, we just
rerun it from 0.
Whereas with the REPL, if
you wanted to make an edit
to something earlier in the
source that you had entered,
you have to, you know,
get the process back
into the state then, you
know, reenter the REPL,
retype everything
making that one change
to see how it affects things.
Playgrounds also supports some
of these higher level futures
like Quick Looks and a timeline
which we do not support, uh,
which the REPL does not support.
If you'd like to learn
more about the REPL,
you can go to the Introduction
to LLDB and the Swift REPL talk.
And we'll go into much more
detail about how the REPL works.
In summary, we think Playgrounds
are a great way to play
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In summary, we think Playgrounds
are a great way to play
with Swift, with Cocoa
and with Cocoa Touch.
We think you can use them
for things like learning,
exploration and visualization
and frankly probably tons
of things which we haven't
even thought of yet.
The XCPlayground
framework provides APIs
for using your Playgrounds
for more advanced things.
So you can do things like
manually capture values
with the XCPCaptureValue API.
You can show live views in the
timeline by calling XCPShowView.
And then you can
also extend execution
for asynchronous operations
with the XCPSetExecutionShould
ContinueIndefinitely function.
Finally, we'd really like to
just encourage you to go out
and give Playgrounds a try.
I think, you know,
they're really approachable
and if you just sit
down with them
for a little bit you'll
find a number of great ways
to integrate them into
your development process.
For more information, you can
contact our Developer Tools
Evangelist, Dave DeLong.
We also have some
information about Playgrounds
in the Source Editor
Help for Xcode 6.
You can also ask
questions about Playgrounds
on the Apple Developer Forums.
We have several related
sessions about Swift this week.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We have several related
sessions about Swift this week.
So there was an Introduction
to Swift session yesterday,
which you can catch
on the video.
We also have an Intermediate
Swift session later
this afternoon.
There's also an Advanced
Swift session tomorrow
which you'll be able to see.
We had an Integrating Swift
with Objective-C session
earlier this morning
which you can catch on video.
And we also have a
Swift Interoperability
in Depth session
later this afternoon.
Finally, if you'd like to learn
more about the Swift REPL,
you can go to the
Introduction to LLDB
and the Swift REPL session.
Thank you all for coming
and I hope you have a
great week here at WWDC.