Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Applause ]
>> Good morning.
Welcome to Debugging in Xcode 6.
So if you had seen our
debugging session last year,
you would have noticed our quest
to bring more relative debugging
information to your fingertips.
This year, we're going to
continue with this mission.
Oh, before I forget, my
colleague reminded me
to introduce myself, but my name
has not changed from last year,
so I'm still Han Ming Ong and
I'm still Debugger UI Engineer.
So, let's briefly look
at what we're going
to talk about this year.
I'm going to talk about
a new feature in Xcode 6
that will help you
with debugging your use
of Grand Central
Dispatch which is GCD.
This feature is called
Queue Debugging.
Next up, Troy is going to come
up and show you amazing new way
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Next up, Troy is going to come
up and show you amazing new way
to explore and debug
your user interface.
And then Kerry is going
to talk in detail,
how to integrate your --
the Quick Look Preview
into your custom class.
I want to set the stage
for Queue Debugging
so that we're all
on the same page.
My apologies if this
is a bit of --
a bit of it too basic for some
of you, but it's important
that we get the fundamentals
right.
So, when your application hits a
break point, the program pauses.
The debugger will go through
a process known as unwinding.
What it does is, it
looks at the method
that contains your break point,
and follows the thread
pointer back to the call site.
In this case, awakeFromNib.
It goes on until it reaches
the beginning of the thread.
Then it comes back with a series
of stack frames known
as a backtrace.
So a stack frame is an instance
of location of your method.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So a stack frame is an instance
of location of your method.
Now backtraces are important
because it helps you
understand the control flow
and the state of
your application.
So what happens -- how
does GCD impact backtraces?
But first, what is GCD?
It is a technology
that is introduced five
or six years ago, in the
Snow Leopard timeframe.
Since then, it has
taken off like wildfire
because it is a very natural
way to create concurrent,
responsive application.
Basically you divide your task
up into smaller work
items called blocks.
And then you enqueue the block
to a queue using two ways:
synchronously or asynchronously.
We're going to focus
on the latter
because it poses
a bigger challenge
when it comes to debugging.
You enqueue asynchronously
using the dispatch async API.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You enqueue asynchronously
using the dispatch async API.
And then what you're
telling the system, the OS,
is at some time later, it
can be dequeue your block
and find a worker thread
to start executing it.
Imagine that you've
hit a breakpoint
in your block right now.
So let's look at a
backtrace of Thread 16.
After the debugger has
finished its unwinding,
the bottommost frame, Frame
9, represents the start
of the worker thread,
which corresponds
to the dequeuing event.
So what do you have to do
to understand the control flow
before the enqueuing event?
Well, what I used to do
is to find the method
that contains the
enqueuing event,
in this case cachedGraphImage,
paste it in the Search
Navigator,
search for all the call sites
of it, put break points there,
re-launch the application,
go through all the
crazy UI gestures
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
go through all the
crazy UI gestures
to make sure I can
repeat the similar --
the same problem to
hit the break point.
And heaven forbids if
those call sites are also
in another dispatch async
because that means I have
to wash, rinse, and repeat.
But, Xcode is not lying to you
when it's giving you
this limited backtrace.
That's because the thread
that does enqueuing did it
asynchronously in the past.
In fact, that thread is possibly
doing something completely
different or may be
gone from memory.
So it's not fair to accuse
a debugger of not being able
to unwind to the past, but in
your head, you must be thinking,
"Well, this is accurate
but surely Xcode can present
a more logical backtrace."
And we agree with you.
So in the scenario that I
described above, over here,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So in the scenario that I
described above, over here,
we're going to splice and
Xcode 6 is going to splice
in the backtrace of
the enqueuing event
so that it can show them to you
in a more logical
manner in the UI.
And if you have one in --
more than one enqueuing event,
Xcode is going to
follow the chain
so that it shows you everything.
So how did we do that?
Well we worked through
several layers of the OS,
down to the core OS, we
shortcuts all the backtraces
of the enqueuing event, so
when your application hits a
breakpoint, Xcode
will ask the debugger
to retrieve the backtrace,
so that we can show
them to you in the UI.
The live stack frames,
they have colored icons.
The recorded stack frames,
they have gray icons.
But, just like the live stack
frame, you can select it
and if Xcode has
its debug symbols,
it will show you the source
code, like in this case.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
it will show you the source
code, like in this case.
If it doesn't have debug symbol,
it will show this assembly
that some among us
can actually decipher.
So why are the icons gray?
Well a recorded stack
frame's icon is gray
because it is a visual cue
to let you know that
it's historical.
And because it doesn't
exist in memory anymore,
you cannot interact
with it in the console.
You cannot run expressions
like [inaudible].
And Xcode will not show
you its frame variables
because recording the frame
variables would cause the
application to blow up the
memory, possibly causing it
to be jettisoned on a device.
So that wraps up the first
part of Queue Debugging.
Moving onto the second part.
Xcode by default shows you the
backtraces in the threads view
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Xcode by default shows you the
backtraces in the threads view
in the debug navigator.
As you can see here,
Threads 5 --
Thread 5 is showing
you its backtrace.
So that just means that
a backtrace is organized
by its parent threads.
There's another equally
interesting view known
as Queue's View in
the debug navigator.
And if you pay attention
to your top right corner,
there's a little control known
as the Process View
Option Selector.
It is a mouthful,
but it is useful.
So if you toggle it to the
Queue's View, Xcode switches you
over to emphasize
the relationship
between blocks and queues.
So in this slide here, you see
that the top queue has
one Executing Block.
So what about the blocks
that here you have enqueued
but not executing yet?
Let's look at this scenario.
So I'm using a Serial
Queue as an illustration,
but this happens with
concurrent queues as well.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
but this happens with
concurrent queues as well.
The green square is your
currently Executing Block.
As long as it has not
finished executing,
blocks that you submit
subsequently to the queue,
will get stacked up behind it.
We call those gray
squares the Pending Blocks.
So in Xcode 6, we're going
to show you the Pending
Blocks as well of a queue.
[ Applause ]
So in this case, we
have 9 Pending Blocks.
The Pending Blocks are like
Executing Block in that
if you twist it down,
it will show you the --
a backtrace which by definition,
is a recorded backtrace
of the enqueuing event.
So we hope that by
surfacing this information,
you can answer questions like,
"How many Pending Blocks have
I submitted to the queue?
Am I'm oversaturating
the queue?"
And if you have literally
tens and thousands of blocks -
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And if you have literally
tens and thousands of blocks -
Pending Blocks - are there
some that are not needed,
because you may be able
to change your algorithm
or your granularity so
that you do less work?
Now doing less work is important
because that would mean
saving battery life
on your customers' devices.
So on top of that, it
will help us solve a class
of programming problems
that I'm going to go
into a demonstration now.
So, running on the simulator
is an application called Jogr
which helps you track
your runs in San Francisco
and keep fit while you're
at -- during this WWDC.
Well, I know, developers jogging
and keeping fit, but
we can all dream.
Now, I have a timer here
that tracks your time
and your velocity,
and a map of all
of the routes that I've done.
And I've done exactly
one this year,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And I've done exactly
one this year,
which is one too many for me.
If you click on the date, if you
select the date, it will slide
in the detail page
of my velocity graph.
So notice that it takes a
little bit of time to slide
in the detail page, and I'm
sure you have learned from Apple
and your customers that
they want your animation
to be smooth: smooth
like butter.
So this is not.
And I want to figure out why.
So things I know to code
pretty well, I'm just going
to jump straight into Xcode
to the class known GraphView.
GraphView is the class
that draws the graph.
And I'm going to jump
straight awakeFromNib by going
to the implementation field
of the [inaudible] bar
and start typing "awake."
There I go.
And I've a method here that
creates my velocity path.
And I know that it is doing
a lot of heavy-duty work,
so let's jump into
the definition
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so let's jump into
the definition
by doing a Command-Click on it.
What I see here is,
it's spending time fetching the
velocity data from the database,
and then it takes a
lock to protect it.
And subsequently go
through each data point
in the velocity data
to draw the path.
And when it's done,
it releases the lock.
So it's doing all this
work on the main thread.
So it's impeding the
detail page from sliding in.
And this looks like
a good candidate
to use this dispatch async.
So let's do that.
Going back to awakeFromNib.
And I'm going to paste --
pasting a chunk of code which
I don't have, but it's alright.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Alright, I'm going to move
the line that creates the path
into the dispatch async block.
And I'm going to
dispatch the block
to a simple queue of the graph.
And when I'm done calculating
the path, I will update it
on the main thread like usual.
So this is a pretty
simple change.
Let's rerun by clicking on the
Run button to see if it works.
Okay, I'm going to go to the
date so that I can select it.
So this time when
I select the date,
the detail page should slide
in very quickly, which it does,
but my graph is not drawing.
So, there are many ways to --
you can try to figure out
what is the problem but one
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you can try to figure out
what is the problem but one
of my favorite way is to look
at the state of the application.
And to do that, I will
look at the backtraces
of the application by
clicking the Pause button
in the debug bar.
And I know that work
for my graph is done
on the Graph Serial Queue,
so I found a thread
which is Thread 22.
I'm going to twist it
open and you see --
you may not be able to see at
the back, but Frame 2 shows
that I'm trying to
wait for a lock.
It looks like it.
I'm going to select
Frame 3 to confirm it.
And indeed, I'm waiting
for the lock.
So those of us who have faced
this situation before have a
pretty standard following
path [inaudible] which is
to find a thread
that has the lock.
So let's do that.
I'm going to show you a nifty
way to show all the backtraces
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm going to show you a nifty
way to show all the backtraces
which is to first collapse the
process item and by holding
down the Option key,
you can twist it open.
So now I'm going to visually
just scan through to look
for the thread that
has the lock.
Well this is interesting
because besides the Thread 22,
which is trying to
acquire the lock,
I cannot find a thread
that has the lock.
So this is a head scratcher.
But what do you know?
We just learned something
that may be able to help us.
So I'm going to switch over
to Queue Debugging by going
to the [inaudible] control.
And here I'm going to use
the filter bar to focus
on my Graph Serial Queue.
So there it is.
So, it says here, I have one
running block which is my --
the block waiting for the lock.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And I have one Pending Block.
To show my Pending
Block, I'm going to go
to my Debug menu
item, Debug Workflow,
and turn on Always Show
Pending Blocks and Queues.
Out pops my Pending Block.
I'm going to twist it open
and select the first frame
which has my source code.
So plotAccelerationGraph --
Curve, is a method which I
enhanced this morning as well,
to use dispatch async so that
I can work off the main thread.
And it looks like in
my haste what I did is,
I acquired a lock before
I did the dispatch async.
So what's going on is this.
I have an Execution
Block waiting for a lock,
and stacked right after
it, is my Pending Block,
which unfortunately
has the lock.
So the Pending Block cannot
move because it has to wait
for the Execution
Block to finish.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So this is a kind of deadlock,
albeit in a non-classical way.
So thankfully the
solution is pretty simple.
I just have to move the
line that does the locking,
closer to the place, where
it's protecting its data,
which is velocity data.
This insures that it
doesn't try to get a lock
until it's dequeued
and start executing.
So with this second
round of simple change,
let's see if this works.
Okay, let's get to the point
where I can select
the date again.
And voila.
Everything looks correct now.
So without this Queue Debugging,
what you would have to do -
what I would have to do - is
to search for all the places
where my velocity data lock is
used and visually look at them
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
where my velocity data lock is
used and visually look at them
and reason really hard
about how it's used.
And that's error
prone and tedious.
In summary, you're going
to get Queue Debugging
in Xcode 6, which has two parts.
Recorded backtrace is
going to get you --
show you backtrace of
the enqueuing event
when you're using dispatch
async and Pending Blocks, by --
hopefully by surfacing
this information,
you can optimize
your use of GCD.
With that, let me bring up Troy
to talk about view debugging.
[ Applause ]
>> Hi, my name is Troy.
And thank you for coming to
our Debugging in Xcode 6.
As you may know, Xcode
is a fantastic tool
for discovering things
about your application
that may be hidden
through the debugger.
Han Ming just showed
us two new features
through the Pending Blocks
and recorded stack traces
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
through the Pending Blocks
and recorded stack traces
that are hidden pieces
of information
about your application
that Xcode exposes to you.
But we all know that
not all of the bugs
in our applications are hidden.
Some of them are
extremely visible.
They're staring us
right in the face,
from the user interface
of our applications.
And since these are visual
bugs, wouldn't it be great
if we could debug
them visually as well?
And now in Xcode 6, you can.
So what kind of bugs
am I talking about?
These are the bugs where you
have a mis-positioned view
or clipping is wrong.
These are the squished
or the stretched views.
And these are the views
that are missing entirely
because the visibility
or "is hidden" attribute is set
incorrectly in your application.
But that's not all
that this new aspect
of the debugger in
Xcode helps with.
You can use it when
you're not even debugging.
Let's say I have an
application like this,
and I would like to add
a new button down here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And I don't know, maybe
it's a new code base to me,
maybe it's been awhile
since I've read this,
I don't know what this
view is behind it.
Wouldn't it be great if I
could just click with the mouse
and find out what that view is?
Well now, you can.
This view debugger feature is
integrated all throughout Xcode.
So let's take a look at
the Xcode window and figure
out where the different
pieces are
so that we know what we're
talking about when we're talking
about this view debugging
feature.
Here is the Xcode window
that we all know and love.
When your application
is running,
down at the bottom
there's the Debug Bar.
This is where you find
your familiar items
such as the Pause
and Continue buttons.
Well now there's a
new button in there,
which is the Debug View
Hierarchy button, right here.
Simply click this,
and Xcode is going
to import the user
interface of your application
into the main editor
window of Xcode.
But it's not just imported as
a static image, it's imported
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But it's not just imported as
a static image, it's imported
as separate pieces so that
Xcode can actually explode it
out into three dimensions and
rotate it around if you want.
Seeing your application in this
3D view is very illuminating.
It allows you to
traverse the hierarchy,
see what the parent views are,
see where the siblings are.
But if you want a more
concrete representation
of your view hierarchy, we
turn to the Debug Navigator.
This is as Han Ming
talked about,
the place where you find
your threads and your queues.
And that's available here
in this Process View
Option Selector.
If you select the View option
in there, now there's threads,
queues, and views, down below
we have, your view hierarchy
in the application
which is right here.
Down below, we have
some filtering options
to help you tame that list.
We have the Show
Only Primary Views
and we have a Show
Only Displayed Views.
Let me stop on this second one,
because this one's important.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Let me stop on this second one,
because this one's important.
If you have a view that's
missing in your application,
and maybe the "is
hidden" is set on it.
And so Xcode is also going
to hide it in the Xcode UI,
but Xcode knows about it.
It could show it to you.
So, you can simply turn off this
option and Xcode will show all
of your views, even the
ones that are hidden.
Finally, there's the string
comparison there, which we'll do
in an exact match of that
list in the navigator
to help you drill down to
exactly the item you're
looking for.
Now let's turn our attention
over to the right hand
side of the Xcode window.
This is the Inspector Area.
And you might be
familiar with this
if you've ever used
an interface builder,
because these are very similar.
We have an object inspector,
and there's a size
inspector as well.
Here we see the object
inspector for a UIImageView.
And not only that, this is
a specific UIImageView
because we're selecting --
we're clicking on one that's
in our application, so we
actually have the address
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in our application, so we
actually have the address
of that object as well,
which is Resident in Memory,
on your Mac of on
your iOS device.
We have the thumbnail and all
the other interesting attributes
about that view listed
in this Inspector.
Finally, we have
the Size Inspector.
This is going to
show you the size
and position, as
you might expect.
It's also going to show a list
of the auto-layout constraints
that are affecting that
view, with two exceptions.
Down at the bottom,
you see two constraints
which are deemphasized.
These are not affecting the
layout of your view currently,
but they're still
attached to the view
and they still have meaning.
In this case, we have
a self.width of 320,
and in the parentheses, you
see that's content size.
That's because the system added
this implicitly to this view
to represent the content size.
They're deemphasized because
up above, they're redundant
with two explicit
constraints that were added
in Interface Builder, and
those also have a width of 320,
in this case, but they
might not always match.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So this is a great
place to check
if you think you're
having constraint issues,
as we're going to see
in a demo which I'd
like to show you right now.
Alright, here we
have the application
that Han Ming started with.
And if you have super,
eagle eyes, or maybe not,
you'll notice that there's a
pretty bad visual bug down here.
I wonder if the View Debugging
in Xcode can help us find that.
So I'm going to switch
over to Xcode,
find this Debug View Hierarchy
button, and simply press it.
What's happening now is Xcode's
going through all of the views
in the application, and pulling
them back into the Xcode window.
Now we see, the user
interface right here.
And already, you're
getting a better look
at what might be the
issue in this application.
You see, some of the
views, some of the images
in this UICollectionView,
are outside the view
where they are supposed
to be contained.
That's a pretty interesting fact
to help diagnose the problem
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
That's a pretty interesting fact
to help diagnose the problem
but it doesn't help us solve
the problem, so we're going
to have to dig deeper.
To explode the View Hierarchy
of you application, all you need
to do is simply click and
drag anywhere in the canvas.
This allows us to see the
parent-child relationships
between some of these views.
I have open on the right
hand side, the Assist Editor
which is in Automatic Mode.
This allows Xcode to track the
file that I click over here
in the view debugger,
with a source code file
that matches with it.
So if I click here, I
get the source code file
for UIImageView.
I'm going to traverse backwards
up through the hierarchy,
until I get to the custom cell
that has been written
for this class.
The parent of this
UIImageView is a UIView,
and this is the Content
View of that cell.
And the one behind that is the
Run-Details Collection View Cell
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And the one behind that is the
Run-Details Collection View Cell
which is custom code
in my application.
I'm also going to open up
the Inspector here and check
out some of the positions
of these views as --
because it looks like there's
probably a position bug here.
So traversing back up the stack,
starting with one of these views
that has a missing image, I'm
going to click here and see
that the position is 160 45.
Its child is 45 45, because
the position is relative
to its parent, but where
is this final view?
I'm going to go over
to the Navigator
and find the view I have
selected is this UIView,
and I can simply find
where its child is.
I don't know where it
is in spatial space,
but I know where it is in the
real hierarchy of the view.
So if I click here, I see
that the position is 160 45.
And remember, that's
based on the parent.
So what I'm actually looking
at is this view over here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So what I'm actually looking
at is this view over here.
I thought that was
a working one,
but the view has been shifted
off of the cell and it's --
that's the reason it's missing.
So let's go back up to the
cell class and take a look
at the implementation
of that class.
I'm going to Command Click on
the class name here to dive
into the implementation.
And here you see a fairly simple
implementation for a cell view.
All it does, is it
overrides the initWithFrame,
it creates a new UIImageView,
and then it adds it as the --
a sub view of the Content
View right down here.
Thinking about the
information we found earlier.
We know that there's a
position issue and I can see
that we're passing the frameRect
of the cell to this sub view.
That's not what I want.
I want the sub view to have
the same bounds as the cell.
So instead of frameRect, I'm
going to type self.bounds.
This should be enough
to fix our problem,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This should be enough
to fix our problem,
so I'm going to build and run.
Switch over to the simulator.
And dive back into
our Run Details View.
Sure enough, we have the fully
functioning UICollectionView
with all our images,
tightly spaced as expected.
Now that that bug's fixed,
I do see another issue.
You see, this label
up here, San Fran,
is kind of a cheeky
nickname for San Francisco,
but this is a serious
running app.
This is an app for those
of us that go every morning
and we don't call this
fair city San Fran.
This is San Francisco.
So let's go back to the
View Debugger and see
if we can understand what
might be going on there.
I'm going to take a moment
to admire the fully
functioning, UICollectionView.
Looks great.
I'm going then turn back
to two dimensional mode.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm going then turn back
to two dimensional mode.
This button down here allows
us to reset the view hierarchy,
and I'm going to
click on this label.
Alright, I know that I'm using
Auto Layout in this application,
so let's go ahead and see if
there's anything having to do
with constraints that
might be an issue.
Down here is the Show
Constraints button.
This, it shows all the
constraints, and it also dims
out the views that are not
currently related to those --
to that view or its constraints.
This allows us to really
focus in on the work at hand.
When I zoom in, it's
plain to see
that there are two constraints
attached to this label.
And if I look over here,
I see the width is 95.
There's an explicit constraint
of 95, but down in the bottom,
the content size is 109.5.
So clearly, somebody added
an explicit constraint
in Interface Builder and that's
clipping the implicit size
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in Interface Builder and that's
clipping the implicit size
of that label.
So I'm just going to switch
over to my storyboard,
find that label, and delete
that explicit constraint.
If I had the time to show you
guys, I would add a constraint
that properly limited that label
so it didn't go beyond
the bounds of the screen,
but I'm sure you can find an
Interface Builder session.
For example, this afternoon
at 3:15 that will go
into more detail about how
to lay out constraints.
And then we have the full
string of that label.
So we've seen that the View
Debugger, is a fantastic way
to look -- take a look
at your application.
And I invite you
to do just that.
Go back today, just after the
session, open up your computers
and just try hitting
the View Debugger button
on your application.
I think you'll find it
illuminating and the integration
with Xcode is fantastic.
Now I'd like to turn
it over to Kerry,
who's going to teach
you a little bit more
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
who's going to teach
you a little bit more
about Quick Look Previews.
[ Applause ]
>> Thank you, Troy.
My name is Kerry.
And how is everyone enjoying
the conference so far?
[ Applause ]
That's great.
I know that we are very
excited to be here as well,
to show some great new
debugging features in Xcode 6.
But first, let's
take a step back.
Last year, Xcode 5 debuted
with this great new feature,
whereby as you are running and
debugging your application,
you can get a live Quick
Look preview of your data.
So simply by clicking
on the Quick Look icon
in the Debug Bar, you
can get this popover
that would show you a preview.
You could even, simply by
hovering over the source
of a variable in
the Source Editor,
get a Quick Look preview right
from there, just by clicking
on the Quick Look icon in
the popover that appears.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on the Quick Look icon in
the popover that appears.
Now, Xcode 5 debuted with
default support for a number
of important and common
object types like images
and Bezier paths and even
things like map locations.
Well, we've gotten a lot of
great feedback from this feature
and I know that it's been
very useful to a number
of developers including myself.
So to build on the success,
in Xcode 6, there is support
for two new object types.
The first is Views.
So whether it be a UIView
or an NSView,
you can get a Quick Look preview
of that, simply by clicking
in the Variables view and
clicking on the Quick Look icon
or my favorite is
just hit the Space Bar
and it will bring
up a nice preview.
And considering how common
views are in most applications,
I think this will be a
very powerful feature.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I think this will be a
very powerful feature.
Now the second object type
that was added is, well,
I honestly don't know.
That's because it's
your own custom class.
So now for the first
time, if you have a class
that does some custom drawing
and perhaps returns a --
an image or a Bezier path
or something like that,
you can now get a
preview of that as well.
Before now, there wasn't
great support for that.
So if you were to try
and get a preview,
you would get this Default View
which had some pertinent
information like the name
and the address and the
type, but no preview.
So I would like to show
you how to fix that.
There's a simple method
that you can implement
in your Classes Implementation
and it's called
debugQuickLookObject.
Now in this class, you can
either call your drawing code
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now in this class, you can
either call your drawing code
or implement it in there,
but the important point is,
from this method,
you return something
that Xcode knows how to show.
So one of the default supported
types should be returned
from this method and then
you'll be good to go.
And I would like to
show you that now.
So here we have the
Jogr application
that we've been seeing
in previous demos.
And I'm going to click
the Routes button,
and we'll see Han Ming's
run from this morning,
if that's indeed the case.
Okay, so this class has a --
an object class called
RoutePathOverlay
which accesses the run data
to generate this Bezier path
that they gets overlaid
onto the map.
So let's look at that
a little further.
Well I'm going to click on the
map and I'm going to hit this --
whoa, scrolls really fast.
I'm going to hit
this break point.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm going to hit
this break point.
And let's say I'm trying
to debug some issue here,
now down in the Variables View,
we can see we've got a number
of local variables
like this point.
And if I click on
the Quick Look icon,
I can see a preview
of the point.
This is our route path overlay.
And if I click on that, so I'm
going to hit the Space Bar,
and what it just comes up
with is just some generic
information, but we can
do better than that.
So I'm going to stop here.
I'm going to go to
our RoutePathOverlay.
And I've got the method
that I was talking about:
debugQuickLookObject.
And it's a sort of a long
title but try and remember.
Okay, and if I uncomment
that, what this method does,
it's not really important
because it's going
to be different for
every custom class,
but what it does is it accesses
each of the 364 some odd points
of map location for that run.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of map location for that run.
And then generates a Bezier
path, scales it a little bit,
and then returns from
it, a Bezier path,
because Xcode 6 knows
how to render
or Quick Look preview
a Bezier path.
So now that we've
implemented that or enabled it,
I'm going to Run
and Debug again.
And we'll go to our routes,
and we'll click on the map.
And if all goes well, we should
see a nice detailed preview
of each of those points
of data from the start
until the ambulance picked up
Han Ming when he collapsed.
Okay. So, what have
we seen today?
We've seen Han Ming show
us how we can very easily
and more effectively
debug queues and blocks
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and more effectively
debug queues and blocks
with the new Queue
Debugging feature.
And then Troy showed us
how we can more effectively
or easily explore, our
application's View Hierarchy.
I've used this very effectively
myself several times.
It's been very helpful.
And then I showed you how
to add Quick Look previews
for your own custom classes.
And remember, you can
also now preview any view.
So for more information, you
can contact our great Developer
Tools Evangelist, Dave DeLong.
I've also got a link
here to the documentation
for Quick Look previews,
which documentation will show
you a full list of exactly all
of the default supported
types in Xcode 6.
And then, don't forget
the developer forums.
There's a lot of great
debugging sessions this week,
so be sure to check them out.
Thank you very much.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Applause ]