Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> KATE STONE: Good
afternoon and welcome
to What's New In LLDB.
My name is Kate.
[ Applause ]
>> KATE STONE: And I manage
the runtime analysis tools
in Xcode, including LLDB.
I will be getting us started
here but I'll be bringing up two
of my engineers,
Sean and Enrico,
to dive into the details
in just a little bit.
But to get us started, I would
like to talk a little bit
about the year's highlights,
some of the changes,
big and small, since the
last time we were at WWDC.
Most notably we shipped
our first Swift debugger.
It is a step forward, obviously,
in being able to write
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It is a step forward, obviously,
in being able to write
and develop the Swift code that
you have come to know and love.
But more importantly it
wasn't our last step.
We continued to improve
that debugger
and we hope your continued
feedback will help us make it
even better still.
At the same time we
shipped the Swift REPL;
it's a little bit different
than your standard request
response REPL environment,
in that it is really
LLDB in disguise.
The REPL is not just a way that
you can ask questions in Swift.
It is a way that you can
debug those questions,
you can actually set
breakpoints in the REPL
and do everything you'd expect
from a debugging environment
because it is LLDB.
If you haven't dug
deep into that,
I'd recommend you take a look at
the blog posts on the subject.
But, of course, that's
not the end.
There are numerous improvements
that we have made since then.
Since we first shipped, we've
made over 100 improvements
in the Swift debugging
experience, and we continue
to enhance the debugging
experience
for Objective-C as well.
We're going to cover
some of them here,
but just to recap some of the
changes that have been made
since last year, Swift types
initially did not show inherited
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
since last year, Swift types
initially did not show inherited
Objective-C fields.
We've since corrected that.
Help now includes
command aliases.
And it is important
to understand these,
because while LLDB has what
may look like a wordy syntax,
we might ask you to type 'help,
in practice there are
a number of short cuts.
And throughout this presentation
we'll use the following notation
to describe them.
Help can actually be abbreviated
to the first unique sequence.
So in this case H is
enough to bring up help.
More importantly, for
more elaborate examples
like expression-O-- , which
means 'evaluate an expression,
tell me the results as
if it were an object
by sending it a method
to describe itself,
and then no more options
followed by the expression,
but you can just type PO.
PO is a handy alias
that is shorthand
for everything to the left.
So, as you get used to
the help, you should learn
to use the aliases, because they
are going to be your fastest way
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to get to some of the
powerful functionality in LLDB.
We've also improved data
formatting, because telling you
about your data is
absolutely critical
to your debugging experience.
So types like set and NS Index
Path now have default formatting
to help you understand
your data instead
of just showing you the raw dump
of the underlying
representation.
Printf prototype
for expressions,
if you've ever tried to evaluate
an expression involving printf,
you may have seen some
slightly suspect results.
That's because the
debugger tries to make a lot
of assumptions about your
expression for any declaration
that it doesn't know,
and it didn't know
printf, in most cases.
So it didn't know that it was
a variatic function, that is,
one that can take a
variable number of arguments,
and didn't know especially
on 64-bit devices how
to pass those arguments
correctly.
That has been corrected
so that all
of your expressions
involving printf for C
and Objective-C should just
work right out of the box.
And then lastly, and
truly lastly, this time,
we have improved the
disassembly format
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
we have improved the
disassembly format
to make it easier
than ever to read.
Digging into some of the more
interesting enhancements,
breakpoint enhancements
were made this spring
that you may not be aware of.
Specifically you can
now name breakpoints.
And it may not seem obvious
why a named breakpoint would be
easier to use than any other
breakpoint, until you realize
that those names don't
have to be unique
and that you can apply multiple
names to a single breakpoint.
You can think of
them a lot like tags.
And all breakpoint
commands take those names.
So I can set a breakpoint
by providing breakpoint set
and dash N, capital N followed
by a name, optionally followed
by another dash capital N and
additional name, and so forth.
But more importantly, once
I've given a breakpoint
or multiple breakpoints a name,
I can then operate on them
with all the other commands.
Breakpoint enable name
will enable all breakpoints
that share that name or,
again, think of it as that tag.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
That is made even more
interesting by the fact
that we now allow you to
set breakpoints in LLDBinit.
If you're not familiar
with LLDBinit,
this is a filename starting with
a prefix with a period that goes
in your home directory that
tells LLDB, here are a bunch
of commands to execute every
time I start an LLDB session.
So if you use these,
you can create a set
of default breakpoints
when LLDB starts,
and all breakpoints you set
before you actually create a
target are inherited by
every target you create.
So combine these two, and I
can write an LLDBinit along
these lines.
A set of breakpoints, -n
everything named malloc,
a breakpoint -n everything
named free,
name all of those breakpoints
memory, and then disable them.
And what this gives me
is a handy way to get all
of my memory handling
breakpoints just
by typing 'breakpoint enable
memory' in any session
that I use thereafter.
So, you'll have your own set,
I'm sure, of handy breakpoints
that you always want
to have access to
and now you can give them
easy to remember names.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and now you can give them
easy to remember names.
But, of course, you are here
not just to learn about things
that we have done
and already shipped,
but the things we are
just starting to preview.
Xcode 7, really important
release,
a lot of improvements here.
An expression evaluation,
notably.
And Sean is going to talk to you
a lot more in depth about this.
Swift 2 support, because, of
course, the language continues
to evolve, as well as
Objective-C support in terms
of advanced handling
for modules.
Some of this we'll
cover in depth,
but some of it is really
just behind the scenes.
If you go digging, you
may notice, for example,
that in Xcode 7, because
we know about modules,
we can actually build debug
information for the module once
and then not replicate
it everywhere else.
This allows us to
drastically decrease the size
of debug information and improve
the performance of compilation.
Once you get into
actual .dSYM file,
that .dSYM file will then
contain absolutely everything
you need.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you need.
But it also contains some
handy other optimizations,
like not duplicating
information for C++ types,
thanks to the one
definition rule,
whereas before we may
have had multiple copies.
In fact, we have seen
debug information winding
up a sixth the size
that it was in Xcode 6,
especially for C++ projects.
We have also improved the data
formatting in a variety of ways.
Vector types now get unique
automatic data formatting both
for Objective-C and Swift.
And, perhaps most importantly,
if you have custom types
in Swift, you can now customize
the way they are presented just
by writing Swift code.
And Enrico will talk
about this in depth.
We have integrated support for
address sanitizer into LLDB.
So not only will address
sanitizer tell you
when you reference
memory that is invalid,
but you can ask questions
about memory.
You can ask, for example, for
the history of memory to see
where it was allocated or
when it was deallocated,
right from the LLDB
console, so the memory family
of commands are ones you
might want to dig into
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of commands are ones you
might want to dig into
and look at the help for.
We've also added
type lookup commands.
The type lookup command will
allow you to get information
about any type in the system.
Basically it's a
header-like representation
that you can get right there
in the debugger to remind you
about the contents of the type.
So, from the LLDB prompt,
all I need to do is type 'type
lookup' followed by a type name
and I'll get a quick
description of that type.
In this case the new
error type that's used
by Swift's error
handling mechanism.
I see that behind the
scenes we have a pair
of properties normally
implemented for you so long
as you're using a EDAM type,
but nonetheless you can see the
details right from the console.
Similarly if I'm
interested in a type
like 'Comparable,' a protocol.
It will tell me that this
protocol actually derives
from two others, so that you
will see that Equatable is
where we get the
equality operator.
The underscore Comparable is
where we get the basic less-than
and then the derived
operators are part
of the Comparable protocol.
So there's a lot of convenient
information you can get here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So there's a lot of convenient
information you can get here.
And like everything else,
remind you that you don't have
to type the full
command 'type lookup.'
TY space L is sufficient
to use this command.
But to dive into more depth,
especially to talk to us
about how we evaluate
expressions,
I would like to invite up
Sean Callanan [applause].
>> SEAN CALLANAN: Hello.
I want to tell you
about compilers in LLDB.
Now you may be saying
to yourself there are
lots of compiler sessions.
Why do I care about compilers?
Compilers are a critical
part of LLDB.
They are what makes
LLDB powerful,
and they are what
makes LLDB easy to use.
It is really powerful because
compilers have a unique
understanding of the way your
program works, the way it lays
out its data, and what you mean
when you say I want to look
at this variable or
call this function.
Another reason the
compilers are so important is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Another reason the
compilers are so important is
because they make it easy
to work with the debugger.
If you want to print something
you just use the code you are
used to typing, pass it
to the expression command,
and the compiler
takes over from there.
So today I want to tell you
about the improvements
we've made
in two important areas related
to our compiler integration.
First of all, I've
got some great news
for you long-time
Objective-C developers.
And then I'm going to tell
all you Swift developers,
whom I hope is all
of you at this point,
about the improvements
we've made there, too.
Let's get started
on Objective-C.
Now, LLDB contains two
separate compilers.
Clang, a powerful Objective-C
compiler and, of course,
since last year,
the Swift compiler.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
since last year,
the Swift compiler.
Our Objective-C compiler
support has been improving
over the years and we have
been adding great new features.
For example, the Objective-C
runtime integration.
So if there's some information
in the Objective-C runtime
that isn't present in your debug
information, we know to feed
that to the compiler so that
you can use lots of classes
without having to
do anything special.
Last year, of course,
we introduced the Swift
compiler into LLDB.
And the Swift compiler already
is a very powerful tool.
And we've used a lot of
lessons that we learned
from integrating
the Swift compiler,
and we are improving
them both together.
Let's talk about how the
expression parser works
with Swift, with a
view of Objective-C.
Let's look at a simple
print command.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now I say print here because
I'm using the p shortcut.
What that actually
means is expression.
Notice the dash dash.
That means everything after
the p command has to be code.
You can't pass extra options
to the command this way.
There are other ways,
as Enrico will tell you,
and as Kate showed you before.
Now here is some simple code
that runs through a loop
and prints the loop
counter each time.
And, indeed, if you run
it you get the numbers
out that you would expect.
Why is this cool?
Well, LLDB and your program
are separate processes.
LLDB has a swift
compiler inside it.
Your program is already
running, but with LLDB's help,
the Swift compiler can inject
the code that you just typed
into your program to run.
That's kind of cool if you
like printing loop counters.
But there's a little
bit more to debugging.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But there's a little
bit more to debugging.
Swift also works
with your variables.
You type in some code.
And the contents of
an array are printed.
Now, this array here
is just a piece of data
that is in your program.
And LLDB arranges to show
that data to the compiler
so that it can generate
the code that you expect.
There is another thing I want
to talk about really quickly.
And that is how Swift
works with the SDK.
When you type an expression like
NSApplication.sharedApplication,
what happens is, first
of all you see the
NSApplication.sharedApplication,
the way you would expect.
But what LLDB is doing is going
out and finding the SDK module
that contains that, giving
the compiler access to it,
then the compiler finds
NSApplication and figures
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
then the compiler finds
NSApplication and figures
out how to use
sharedApplication.
That's all great and it
is automatic in Swift.
In Objective-C it
doesn't always work.
So let's try all these things
in Objective-C and some
of you may be getting a little
bit apprehensive at this moment,
because you know that trying to
NSLog something isn't as easy
as it sounds in the debugger.
Well, in the past when
you've typed in NSLog,
you've seen errors like this:
NS log has unknown return type.
That's because in
the SDK, sure enough,
there's a definition of NSLog.
But what LLDB sees
is only what's
in the debug information
in the symbols.
In this case, all
it sees is a symbol.
That symbol, we don't know
what its return type is
and we don't even know that
it takes a format string.
Well, the good news is,
we fixed that [applause].
>> SEAN CALLANAN: NSLog works
the way you would expect.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, let's try something a
little bit more underhanded.
Print NSMakeRect.
Wait a second!
Why is this underhanded?
It's right there
in the frameworks.
Unfortunately it looks like this
identifier doesn't even exist.
Now, you may know
that if you use NSLog
and you cast the result,
yeah, you can use that.
But with NSMakeRect
you can't even do that.
That's because NSMakeRect
is defined NS-Inline.
There is no symbol for it.
What LLDB sees is nothing.
Good news.
No problem anymore.
[ Applause ]
>> SEAN CALLANAN: Just
one more pain point left.
Now let's look at
the old NSApplication
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now let's look at
the old NSApplication
sharedApplication case.
Sure, if you ran that
expression by yourself, yes,
it would work in Objective-C.
I mean, we have been working
on the Objective-C
runtime integration.
But if you try to get out the
undo.Manager you quickly see
that the runtime doesn't
tell you everything.
In particular you
get this weird error
about undo.Manager not being
found on an object of type id.
What is going on there?
In the SDK, sure enough,
sharedApplication returns
an NSApplication star.
But if you look at the
runtime, what it returns is id,
a generic Objective-C object.
Great news.
That is no longer a problem.
In fact we see information
that we can only find
out from the SDK such as that
that pointer is nullable.
This is some of the great
new SDK support for Swift
that just bubbles down
into Objective-C as well.
But the information
is right there.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But the information
is right there.
And that's the philosophy
that we've applied here.
Read straight from the SDK.
Your code has always
worked in LLDB.
We knew about local variables,
functions, your own classes.
SDK functions, on
the other hand,
we had a little bit more
issues with, as you see.
SDK classes like NSView
and NSApplication, yeah,
we saw them but, as you see,
because of the runtime
integration,
there was a little bit
of an asterisk there.
Now, SDK constants, if
you ever tried using
NSASCIIStringEncoding
in an expression,
you know that never flew.
And if you tried using macros
like int-max, and, you know,
max, to take the
largest of two numbers,
that wasn't going
anywhere either.
Well, all of that is
fixed in the latest LLDB.
[ Applause ]
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> SEAN CALLANAN: And we got rid
of the annoying asterisk,
too [laughter].
>> SEAN CALLANAN:
Now, you may say,
how many easy monthly payments
of 39.95 do I need to make
to get this functionality?
Well, good news, it is all free
and the way you do
it is @import AppKit.
You just run an expression
that says import the
frameworks I care about,
if you pull in AppKit,
or for the two
or three iOS programmers among
you, import UIKit, this works.
Now, we haven't been standing
still with Swift either.
Swift 2.0 has great
error handling support
and LLDB is right off
at the bat supporting
that just the way
you would expect.
We can handle Swift errors and
you don't need to call 'try'
when you are calling functions
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
when you are calling functions
that could throw
errors in expressions.
The reason is because
we catch stuff for you.
If you type this
function 'throws' and pass
that to an expression,
notice this is the
same as the p command.
You will get an error
variable created for you
that contains the error
that that function threw.
You can also do this
in the REPL.
If from the REPL prompt,
you do the same thing,
you get an error variable.
Now, let's look at a little bit
more detail of LLDB support.
And that is, you
don't always want
to see what the resulting
error was.
You want to know what was the
code that threw that error.
Well, the way you've done this
in Objective-C is
you used breakpoints.
Specifically you set breakpoints
on Objective-C exceptions.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Specifically you set breakpoints
on Objective-C exceptions.
The way you did this was you
used the breakpoint set command.
You specify that you want
to set the breakpoint
for the Objective-C exception,
and we set that breakpoint
for you.
Now whenever your
Objective-C code tries
to throw an exception,
we'll stop.
You can do the same
thing with Swift errors.
Just replace the
Objective-C with Swift
and we'll stop whenever
your program wants
to throw a Swift error.
But there's another cool
thing that you can do.
And that is you can stop on
specific types of errors.
This is something
we support in Swift.
And the way you do it is very
simple, it's very similar
to the way you would set an
expression breakpoint anyway.
You use the dash O parameter,
which specifies the type name
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You use the dash O parameter,
which specifies the type name
of the error you want to catch.
Now if you do that, you
will stop only when the type
of error you're interested
in would be thrown.
Now, finally, of course you can
still catch errors the way you
would in normal code.
After all, the REPL is meant
partially as a way to learn
and explore the way
the language works.
If you import Foundation
to get an NSError
and then you write some
code that throws an NSError,
you can catch that
NSError and print it.
If you do that, the output
will be exactly the same
as if you had caught
it in your own program.
So I hope you go out of
this remembering two things.
First of all, add import your
modules, and second of all,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
First of all, add import your
modules, and second of all,
try playing around with
error handing in LLDB.
It's a great place to do it.
Now, for much more
detail, not about how
to tell your program what to do,
but how to print the information
your program produces
after it's done it,
I would like to call
up Enrico Granata [applause].
>> ENRICO GRANATA: Hi!
I was in the Labs this morning.
And we were trying to look
through a problem and one thing
that came up is, why can
I not see this variable?
What's up with that?
And in order to help
us figure that out,
we tried several commands.
We tried expression, we tried
PO, we tried frame variable.
And people usually at this
point ask, why do you have
so many commands to do
pretty much the same thing?
Look at my data, see what
is happening in my program.
Well, all of you here get
the insider scoop now.
Let's look at the
commands that LLDB has
to let you look at data.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
There's three of them.
Frame variable, the expression
command, which is the p command,
the expression dash uppercase O,
which as you've been
told before,
you know as the po command.
First one, frame
variable command.
The frame variable command
which you can shorten as frv
when you type it, is pretty
much the Xcode variables view.
It lets you look at all
your local variables.
It lets you look at only a
few of your local variables,
and optionally you can
also apply formatting
with the dash dash format flag.
One thing I want to highlight,
because I will get back to it,
is when you see that
Tuple in the first output,
that is an aggregate,
that is an object
that contains other objects.
The things that are
within that aggregate,
we call them children.
The expression command is
the command you've seen a lot
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The expression command is
the command you've seen a lot
in this session.
I'll be really brief.
Of course, with the
expression command,
you can do simple
arithmetic, as you'd guess.
It is totally possible
to use previous results
and actually do more
stuff with them.
And of course, the expression
command also knows how
to do custom formatting
of your results.
One thing I want to point
out, once again, children.
Third command, the po command.
This is probably the
command that all of you
who are Objective-C developers,
I'm guessing quite a few prior
to Objective-C code, and
you know the po command.
You can create objects and get
their description printed out.
You can just create an NSArray
or print the existing NSArray
and you'll see the
contents of it.
Or, guess what, it
simply works for a string.
So, three commands.
They don't all do
exactly the same thing,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
They don't all do
exactly the same thing,
as you probably guessed by now.
Actually, they are
somewhat similar
and not at all identical.
For instance, the
expression command
and the po command are
'run my code' commands.
Whatever code you type,
these commands will run it.
But then the frame
variable command
and expression command
do step 2 differently.
When they have to
show you your result,
they use the LLDB
formatter system.
We talked quite a bit about
the LLDB formatter system
in past WWDC sessions.
And you should totally
go check them out.
But really briefly,
LLDB has knowledge
of some built-in system types
and automatically formats them.
NSArray, NSDictionaries
with strings.
And it is possible for you
to provide your own format
as written in Python.
On the other hand,
the po command will not
use LLDB formatters.
The po command runs some more
extra code behind the covers,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The po command runs some more
extra code behind the covers,
behind the scenes, to actually
produce the result it has
to show you.
You probably have written at
least one description method
in one of your Objective-C
classes and then you realized,
oh, that's what po prints.
Now I want you to think for a
second about these two models
of actually taking your object
and producing data for it.
The LLDB formatter's model
is what we call the 'out
of process' formatting model.
Why? Because the formatter
sits outside of your process.
It is either built
knowledge into the debugger
or you brought some Python
script to represent your object.
It's different languages,
different files
that live in different scopes.
On the other hand, that external
formatter lives in the dugger.
It is really easy for
that guy to get access
to all the knowledge about your
program that the debugger has.
It's kind of like a bird's
eye view of your process.
Because of that, it's also
really easy for this kind
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Because of that, it's also
really easy for this kind
of formatter to make sure
that your program
state is not changed.
You don't want to change
the state of your program
as a result of looking
at data in the debugger.
The debugger is kind of
like the stage inspector.
It looks at things and
tries not to change them.
The other model, the po model,
the 'write a description
method' model is an in-process
formatting model.
You write your data and
your formatter together,
you write them in
the same language.
You probably even write
them in the same file.
And because your formatter
is just code that runs
in your application, it
gets easy and full access
to the object model
of your application.
But with great power,
comes great responsibility.
You want to make sure that your
formatter does not change the
state of your program.
You want to make sure you don't
do anything in your formatter
that will alter the object
you're trying to represent.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Well, you say, okay,
Objective-C has an in-process
formatting model.
I can write a description
method,
the debugger will pick it up.
What about Swift?
Turns out, and once again,
those of you that are
in this room get
the insider scoop,
that Swift has had an
in-process formatting model
since the very beginning.
But, where is it?
How do I use it?
I hope all of you have
used the Swift playground.
If you have used the
Swift playground,
you have used the Swift
in-process formatting model.
It has been there
since the beginning.
So what is new?
Now in Xcode 7, we take
that very same model,
we make it public API.
It is available for you to use.
And it still powers
the playgrounds,
but now it also powers
the LLDB po command.
Now you've got the
right Swift formatters
for your Swift objects.
How? Let's look a little
bit under the cover.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
How? Let's look a little
bit under the cover.
The model is based
upon four protocols.
These are their names.
Yes, I said four protocols.
And their names are
also quite lengthy.
But I wouldn't worry
too much about that.
It's possible to only opt-in
partially to this model.
The four protocols
doesn't mean you have
to conform to all of them.
You can choose a subset to
get the result you want done.
>> ENRICO: Conform to those,
do that work, and profit.
Let's look at the protocols.
CustomStringConvertible is
the protocol that tells,
that tells us, how would I
print my object as a string?
It doesn't only tell LLDB.
It also tells Swift.
How? The Swift print function,
as well as the Swift string
interpolation feature,
both use the
CustomStringConvertible
protocol.
That's a lot of benefit.
How hard can it be to get it?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
How hard can it be to get it?
It's pretty easy.
I have a data structure
that represents the bottles
of beer song, because I'm
preparing myself for the bash.
And I want to print the lyrics.
I create an instance of that,
and I say, how many bottles
of beer are on the wall.
But that's for when
everything in my app works fine.
If I'm debugging it,
maybe I need a little bit
more information.
That's where Custom Debug
String Convertible kicks in.
It's a debugger specific
representation of the object.
What debugger-specific means
is really up to your app.
It's really up to the
semantics of your object model.
But, as a hint, the
debugPrint function will default
to choosing this protocol.
Of course, both print and
debugPrint will fall back
to the other conformance if
their favorite one isn't there.
How to get this to work?
Pretty simple.
Let's extend our
bottles of beer.
Because we are debugging, we
want to know a little bit more
about the bottles of beer on
the wall, so we can just check
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about the bottles of beer on
the wall, so we can just check
that they are all correctly
stout, and it is going
to be a great bash
because they all are.
Third protocol is Custom
Playground Quick Lookable.
As the name implies,
this protocol is
specifically for playgrounds.
It is meant to provide rich
graphical representations
of your object in a playground.
You want an example?
Sure thing.
I can write a data structure
that represents a person,
and then I can get a
depiction of a person to show
up in my playground
sidebar as a result
of creating an object
of that type.
I'm quite sorry to disappoint
you guys, I really wanted
to get this to happen.
But, unfortunately the t-shirts
with my person will not
be sold at the conference.
Sorry. But I have something
to make up for that.
The last protocol in the lot,
the Custom Reflectable protocol.
It allows us to invent
a entirely custom
children hierarchy.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Yes, I said I would get back to
the word 'children' and I did.
When I say an entirely
custom children hierarchy,
what I mean is that
I can make a new --
I can make a new
structure for my object.
I can tell the language,
I can tell the debugger,
I can tell the playgrounds,
this is what my object
is actually made of.
This is how you should see it.
And the way you do this, the
currency that you transact in,
when you're trying to describe
the structure of objects
to Swift, is called a
Mirror, reflectable mirror.
Let's see an example,
without further ado.
I have an application
whose job it is
to collect temperature samples.
It has got a couple
data structures.
One that describes a moment
in time, and one says,
for a given moment in time,
this was the temperature
information I got.
And then we have got
temperature samples, of course.
Now I'm debugging this app.
I'm trying to see
what is going on,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm trying to see
what is going on,
how it's processing the samples.
So I say po temperatures.
And that's what I got.
Honestly, you know, I
look at it and I say,
it is not bad for a default.
But I immediately see
a couple things I want
to change about this.
Why stack time on two lines?
I really wish it
was all in one line.
And it would be great
if it was in a.m.
/p.m. format, too.
And that temperature, I
look at it and I'm like,
what scale is that in?
I don't even know.
Is it Kelvin, is it
Reaumur, is it Rankine?
We are in America and
we want our Fahrenheit
degrees [laughter].
>> ENRICO GRANATA: Well, the
good news is that we can fix all
of these things, in two steps.
Let's go. Step one, let's get
the time printed on one line.
Here is what I did to get
that to happen for me.
I used an NSDate formatter.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Because I got to run
within my application,
because the code I'm running
to format this object is
actually just normal Swift code,
it is just code I would normally
write as part of my app,
whatever framework,
whatever library,
whatever technology my
app would normally use
to get this job done, I can
just use it in my formatters.
In this case NSDate formatter.
Step two, let's get those
Fahrenheit degrees going.
How do we do it?
We create a mirror.
Here we are.
Now we are saying that our
temperature data object is
structured as a container
of three things.
A time, a temperature
in Centigrade,
and a temperature in Fahrenheit.
The time is the string
interpolation
of the actual time data
stored inside the object.
And because it is
string interpolated
and because we provided a custom
string convertible conformance,
that will be automatically
picked up.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that will be automatically
picked up.
One more thing worth
noticing here is
that when I get both scales,
when I get both Centigrade
and Fahrenheit for
my result printing,
I don't change the value
stored inside the object.
Of course, you say, you don't.
Well, it is actually quite a
bit important to remember not
to change the state
of your program
by writing in-process
formatters.
And now that we've done all this
work, now we've got all this,
now how do we benefit?
Well, we could try
po-ing that again.
And here we go.
And now I look at it again.
I see my object.
And I can look and I see now
that at 6:30 p.m.
it was 93.2 degrees.
Yup, in case you are
wondering, it was really hot
in Cupertino yesterday.
And now we did this work but
we did it because we were smart
and we did the work
ahead of time.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Sometimes I'm trying
to debug something
and I got my program
just where I want it.
I have got this one
hard-to-reproduce bug
to finally happen.
But now it is really
hard to look at the data.
The data is confusing,
it's complicated.
And I wish I had done
this work before,
so that now I could
actually look
at my data in much simpler ways.
But alas I haven't.
All hope is lost.
Nope! No, it isn't!
You can add conformances
and runtime, too.
Through the expression parser
you can add these conformances
and run while debugging
your app.
On the other hand, you
cannot change them.
Existing conformances stay.
You are in the REPL,
you're experimenting.
You really wish you
could po something.
Oh, how I wish I could
add a conformance.
You can do that in
the REPL as well.
And, of course, but I'm sure
you all expect that, guess what?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And, of course, but I'm sure
you all expect that, guess what?
In playgrounds, too.
Look at that!
It seems to me that a lot
of this work that we've done
over the last year in
debugger land that you've heard
from Kate, from Sean, and from
me, has to do with making sure
that it is really easy to access
as much of your information
as possible while
you are debugging.
Access to the Objective-C
runtime gives you more insight
into fields that before
were unavailable to you.
The SDK modules offer an
unprecedented level of access
to the operating environment
that your application is
running in, more types,
more functions, even macros.
And in-process formatting,
in-process formatting
is a great way for you
to create compelling
representations of your types,
that apply across the board.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that apply across the board.
They apply in the playgrounds,
they apply in the REPL,
they apply in the debugger.
For more information, of
course, do not hesitate
to visit our website,
Swift language docs,
or Developer Forums, of
course, the Labs, and Stefan,
our Evangelist, is
but an email away.
Thank you very much,
and have a great WWDC!
[ Applause ]