Discover Xcode's enhancements for debugging autolayout issues at runtime. Learn how issues inside complex GKStateMachine objects can be easily debugged at runtime. Gain insight into finding performance bottlenecks inside SpriteKit and SceneKit apps more easily with the enhanced FPS gauge. Understand how to fix leaked and abandoned memory in your app by inspecting the heap from within your typical Xcode debugging workflow.
And welcome to Visual Debugging with Xcode.
I'm Chris, and I work on Xcode's debugger UI.
You know, debugging tools have come a long way.
It wasn't all that long ago
when our debugging tools looked something like this.
A little while later, with advancements in UI,
our debugging tools began to look more like this.
But fast-forward to today,
and our debugging tools have become much more powerful while
at the same time becoming much easier to use.
A big part of this is because the tools are becoming more
visual, which helps us to solve problems faster
and more intuitively.
Today, my colleagues and I are going to tell you
about the latest in Xcode's visual debugging tools.
First, a quick overview of what we'll cover.
We're going to tell you about a new feature of Xcode to be able
to report on issues detected by the tools at runtime.
We're going to tell you about the latest enhancements
that we've made to Xcode's view debugger
and how we've made auto layout debugging easier
than ever before.
We're going to tell you about a new feature to be able
to visually debug state machines and enhancements we've made
to the FPS performance gauge to help with debugging SpriteKit
and SceneKit frame rate issues.
Finally, we're going to tell you about a new feature of Xcode --
a visual memory graph debugger.
Let's get started by talking about issues.
We all know that build time issues
such as compiler warnings, errors,
and static analysis issues are well-supported
by Xcode's user interface similarly
for our issues detected while testing.
However, the same can't be said for issues detected
by our expanding suite
of runtime debugging and analysis tools.
These tools have been left behind
with their best option being to log their output to the console.
Not the best experience.
We thought we could do much better.
In Xcode 8, we're introducing runtime issues.
Runtime issues elevates the issues detected by the tools
at runtime to the same status in the UI
as traditional build time issues.
The Activity Viewer will display this indicator
when any runtime issues are detected,
along with the number of issues reported.
We've enhanced the Issue Navigator
with a new runtime scope.
This separates the issues detected at runtime
from the traditional build time issues
such as compiler warnings, errors,
and static analysis issues.
So what issues will you expect to see reported at runtime?
In Xcode 8, we're tackling three areas.
The first -- threading issues.
Our brand-new Thread Sanitizer is able
to detect threading issues in your application at runtime.
UI layout issues.
We've expanded Xcode's view debugger to be able
to automatically detect ambiguous layout issues
in your app at runtime.
Our brand-new memory graph debugger,
which we'll talk a lot more about in a few moments,
is able to automatically detect leaked memory
in your application at runtime.
So, as you heard about on Monday,
Xcode's latest runtime sanitizer is the Thread Sanitizer.
Thread Sanitizer helps us to detect
and better understand threading issues
in your applications at runtime.
It can detect such issues as data races,
uses of uninitialized mutexes, unlocks from the wrong thread,
thread leaks, and unsafe calls in signal handlers.
If any of these issues are detected,
they'll be reported as runtime issues.
Thread Sanitizer is a powerful new runtime analysis tool.
You can learn all about it by watching the Thread Sanitizer
and Static Analysis session.
View debugging is a great example
of Xcode's debugging tools becoming more visual.
Only in the last couple of years for debugging UI issues,
we've gone from having to read debug output
in a console like this to this.
Xcode's visual view debugger is a much better experience
for debugging and understanding visual UI issues.
If you haven't used it before,
while Xcode is running your application,
just tap the Debug View Hierarchy button
down in the Debug Bar.
Xcode will snapshot your application,
snapshot your view hierarchy, and explode it
out in an interactive 3D scene.
From there, you can inspect the structure of the view hierarchy
in the 3D canvas and in the outline view.
And you can inspect the properties of all of the views
and constraints using the inspectors.
In Xcode 8, we've made view debugging -- can you guess?
Better than ever.
Snapshots are now up to 70% faster.
So you can go from running your application
to debugging UI issues quicker than ever before.
The rendering of complex layouts
and transformed views is much more accurate in Xcode 8.
And speaking of accuracy, Xcode can now render blurred view,
such as visual effect views with high fidelity in the canvas.
So what you see in Xcode's view debugger more accurately
reflects what you see on device.
You'll see the blur rendering improvement land in beta 2.
We've added conveniences, such as being able to jump directly
to the source code from a view class.
Just tap the Jump button in the Object Inspector.
And navigator filtering is much more powerful, too.
You can filter by any text in a label
or text in a button's title.
Or you can filter by class names,
and that will include super class names.
For example, if you filter by UI label, you'll get back all
of the subclasses of UI label in your view hierarchy.
You can even filter by memory address.
So you can quickly find that particular view just
by knowing its address and memory.
We've got some great improvements
for auto layout debugging as well.
We show many more properties related to auto layout
in the inspectors,
and constraints are better represented in the canvas.
We now render badges on constraints
to represent inequality or aspect ratio relationships.
And we render non-required constraints with dash lines
so you can easily differentiate between required
and non-required constraints in the canvas.
But my favorite new feature for auto layout debugging is
in conjunction with runtime issues.
Xcode is now able
to automatically detect ambiguous layout issues
in your view hierarchy at runtime.
So how does this work?
While snapshotting your view hierarchy,
Xcode will inspect every single view and is able
to accurately determine if any
of those views have ambiguous layouts,
along with the reason for the ambiguity.
If any layout issues are detected,
they'll be reported as runtime issues.
So you'll see them indicated in the Activity Viewer,
and you'll see them listed
in the Issue Navigator under runtime.
Furthermore, the view hierarchy outline will badge any views
that have layout issues, so you can easily spot them
in the context of the whole view hierarchy.
For a selected view, the Size Inspector will contain details
of any layout issues, along with all of the constraints
that participated in the layout for that view.
We're really excited about Xcode's new ability to be able
to automatically detect ambiguous layout issues
And I'd love to give you a demo.
So I have an iPhone here,
and I've got it connected to this Mac.
We've got Xcode up and running a project called DemoBots.
That's one of our sample code projects
that we've updated to Swift 3 this year.
On the right, I'm just using QuickTime Player
to stream the device's screen back
to the desktop so we can all see it.
Our team was tasked with adding an in-game instruction manual
to DemoBots, so we implemented a How To Play screen.
However, we had some issues that we found before the session.
So now is a great opportunity to debug those issues.
I'll tap How To Play.
And this is our How To Play screen.
Not so great is it?
Obviously, we have some issues, so let's take a look.
We can see the DemoBots logo at the back, and there's some sort
of mangled text rendered on top.
So we need to debug this.
Where do we start?
I'll give you some clues.
DemoBots is a little arcade game written in SpriteKit,
but this screen has been laid out using UIKit and auto layout.
So a good place to start is to look under the hood
at the structure of the view hierarchy and all the layouts.
So let's do that now.
If I return to Xcode, down on the bottom,
we can use the Debug View Hierarchy button,
which I'll click now.
And that pauses the application
and snapshots the entire view hierarchy.
In the editor, we now get back an accurate representation
of what we were seeing on screen.
And then to look under the hood at the structure,
all we need to do is drag in the canvas
and we get the whole view hierarchy exploited
out for us in the 3D view.
Here, we can see all of the views that make
up this particular screen -- the window at the back,
container views, visual effects view, and then the views
that make up the How To Play instructions.
Let's zoom in on those.
We see the DemoBots logo at the back,
and then a bunch of labels and images.
And we quickly get some insight by panning around the reason
for the mess we see on screen.
All of these views have been laid
out one on top of the other.
So we've got a layout issue.
Now our traditional workflow would be to inspect each
of these views and their constraints and try
and determine the reason for the layout issue.
But in Xcode 8, we have some additional
Notice up here in the Activity Viewer Xcode is reporting
that we have some runtime issues.
We could click on that one, and that would take us
to the issue navigator.
But you may also notice that over here on the left
in the Debug Navigator,
Xcode has badged some of the views for us.
And that's telling us that these views have layout issues.
So let's go straight to here.
If I select the first view,
that highlights the view in the canvas for us.
And let's open the Size Inspector for that view
over here on the right.
Here, we can see
under constraints the reason for the layout issue.
This view has an ambiguous vertical position.
Now that means that auto layout doesn't have enough information
to be able to unambiguously position this view
in the vertical dimension.
Typically, constraints are missing.
Let's have a look at the next view.
That has the same issue -- vertical position is ambiguous.
And so does the next one.
If I randomly click on a few more,
it looks like they all have the same problem.
What I find curious is the very first sub-view
in this list is not badged with an issue.
So that could be a clue when we get to the layout code.
Let's go to that now.
If I select the Parent View, which has a class name
of InstructionsLayoutView, this is the view responsible
for laying out this How To Play screen.
So let's jump to the source code for that.
An easy way to do that is to select the view.
And over here on the right, we will find
in the Object Inspector a button where we can jump directly
to the source code for that view.
So we'll do that now.
We'll close the Inspector to give us some room.
And let's take a look at the source
It starts by iterating over each of the parts
of the instructions, which are just model objects
which describe section headers, section paragraphs, and images.
And the code lays these out top-to-bottom.
So for each part, we fix the view and we add it
to the view hierarchy.
Then we have some code for the horizontal layout.
But we didn't notice any issues with horizontal layout,
so let's skip over that to the vertical layout.
Here, we have two paths.
The first is for the very first sub-view to constrain it
to the top of the container.
Well, we already noted that the first sub-view wasn't reported
as having any issues.
So, that constraint we assume is set up correctly.
So let's jump to the other side of the conditional.
Here, we're evaluating an optional previousPartView.
And if we have it, we assign it to the local variable above you.
And then we can constrain each view to the view above it.
It looks like this is the constraint that's missing.
So let's have a look at why this conditional is not
If we select previousPartView -- we'll start with that one --
I'll use Command-A to select it for search
and Command-F to get the Find Bar.
Let's look for instances of this variable.
We see it's defined at the top.
It's set to "nil" before answering the fore loop.
We evaluate it down here,
and then we evaluate it again outside of the loop
to handle the bottom constraint.
But it looks like we're never assigning to it.
So let's quickly fix that.
So at the end of the loop, we can set previousPartView
to the current partView.
And then on each iteration,
we'll have the previous view available,
which will be assigned to above you.
And we'll set up the constraint from a view to the one above it.
Let's stop and rerun it and check our work.
And I'll bring QuickTime to the front.
Just note how much information Xcode was able
to give us before we even got to code.
We use view debugger to look under the hood at the structure
and get some insight into the problem.
But more than that, Xcode proactively told us
about some layout issues in our application,
which views had issues,
and specifically what those issues were.
So that gave us a lot of insight before we even got to the code,
so we could quickly zero-in on the part
of the code that we needed to.
Now that our application is running, I can tap How To Play.
And there, it looks much better.
We have a nice-looking instructions screen.
So Xcode is now able to report on issues detected
at runtime using the same UI as we did for build time issues.
Xcode's view debugger has great enhancements this year,
including faster snapshotting and more accurate rendering
of complex layouts and blurred views.
We've got some great enhancement
for auto layout debugging as well.
In particular, Xcode is now able
to automatically detect ambiguous layout issues
Xcode's view debugger supports debugging UIs
on Mac OS, iOS, and tvOS.
Give it a try with your projects, and we'd love
to hear feedback on how it helps you
with your debugging workflow.
And with that, I'd like to hand over to Tyler who's going
to tell us about debugging state machines and frame rate issues.
Today, I'll be showing you a new way you can enhance your
debugging experience with the State Machine Quick Look,
as well as some additions made inside the FPS performance gauge
for Xcode 8.
Today, we have a number
of useful Quick Looks already available inside of Xcode 7,
and these provide you the ability to view a wide variety
of objects live during your debugging.
And you can even provide your own custom Quick Look
to view objects within your app.
And now in Xcode 8,
we're extending our built-in Quick Looks
to include state machines.
So let's first dive into what exactly a state machine is
and how you could use it within your app.
So, many of you may already be familiar with GKStateMachine,
which was part of our release of GameplayKit last year.
And it's available on Mac OS, iOS, and tvOS.
State machines allow you to more easily define complex behavior
by structuring it as a directed graph.
And within a state machine,
you provide discrete behavior for each state.
This could be something as simple as an animation
that will play, or something more complex like an AI.
And then for each state, you define the conditions
by which the state machine will transition
from one state to another.
Once assembled, state machines can produce remarkably
However, they can quickly become difficult to visualize in code
as they expand in complexity.
And simple state machines can quickly evolve
into far more elaborate ones.
In Xcode 7.3, our support
for debugging state machines was limited to the current state,
as well as its transitions.
However, now in Xcode 8,
we're able to visualize the entire state machine
so that you can see exactly what's going on.
This is incredibly useful whether you're operating
with very simple state machines or whether you're working
with much more complex state machines.
With Quick Look, you're able to quickly debug potential issues
and evaluate exactly what's happening
within your state machines.
So, now, let's shift our focus over to performance.
Any time you're creating any sort of game or visual app,
maintaining good performance is key.
And in Xcode 8, we've expanded the FPS performance gauge
to help you with this.
Many of you may already be familiar with parts
of the FPS performance gauge from Xcode 7.
And at the top of the report, you're provided a number
of real-time statistics.
This includes your frame rate, which is the current number
of frames being rendered per second,
as well as your GPU utilization to see which parts
of your GPU are being used the most, and your frame time
for both the CPU and the GPU.
This helps indicate
to you whether you may be CPU-bound or GPU-bound.
Now, in addition to real-time statistics,
Xcode 8 now provides you a timeline history
of your SpriteKit and SceneKit's frame time
for both the CPU and the GPU.
This is available on iOS and watchOS.
And what's great about this is
that we breakdown your CPU frame time and its individual parts
so you're able to see exactly how much time is spent
rendering, or running your update loop,
or evaluating actions and physics,
and even how much time is spent idle.
And when your app is paused, you're able to scroll
through the history of your app's performance
so that you can see how it evolves
as you progress through your app.
And if there's a particular sample you're interested in,
you can dive deeper to examine finer details on it
and get some exact timings.
So let's take a look at how we can use these within our app.
So now that we've addressed the layout issues that we've got.
In our How To Play menu, let's go ahead
and dive into the game itself.
The objective of our game is to convert all
of the corrupted robots within our computer into good robots.
And to do this, I have a beam that can zap them
and reconfigure them into good robots.
Now we see here I've already got a bad robot trying to come
after me, so I'll use my beam to zap him.
So you see he's been converted
to a good robot -- indicated with green.
But I see that we still have a part of our beam present
above our character, and this shouldn't be the case.
Now since we're using a state machine to manage the behavior
of our beam, this is a good candidate
to use the State Machine Quick Look to figure
out what's going on here.
So I'll go ahead and pause our app while I navigate
to our BeamComponent.
Now our BeamComponent is where we create
and update our state machine
that manages the behavior of our beam.
And I'll add a breakpoint here on our update loop
and resume our game so that we hit
that break point immediately.
So now that we're paused, I can go into debug area
and find our instance of the state machine,
and we can Quick Look it.
And from here, we can see the entire state machine.
In blue, we see the current state that we're in,
which is the BeamFiringState.
And in gray, we see all of the additional states
that comprise our state machine.
Now we also see the transitions between each of the states.
And one thing that I've immediately noticed is
that we have a number of transitions
into our BeamFiringState but we have no transitions out of it.
So this means, as soon as we get into our firing state,
we have no way of leaving it.
So let's go ahead and take a look at our BeamFiringState
to see what's going on here.
So I'll remove our breakpoint and close our debug area
and switch to our BeamFiringState.
Now we'll take a look at the update loop.
And I see here we have some logic to transition both
into the CoolingState as well as the IdleState.
But down here in our method
where we're checking whether the state we're trying to transition
to is valid, we're always returning false,
which shouldn't be the case because we want to transition
to either cooling or idle.
So I'll go ahead and fix that by checking whether the state we're
trying to transition to is either of the two valid ones.
And we'll go ahead and rerun our game
and check whether this has addressed the issue
that we were seeing.
Now when we transition to the FiringState
and meet the conditions to exit it, we should properly be able
to transition back into our IdleState.
So I'll jump back into the game and go ahead and fire
at the corrupted robot to convert him into a good one.
And we'll see the beam is no longer present above our player,
so it looks like we've addressed the issue.
So now we've also noticed a performance issue
within our game.
We have a number of ground robots here on the bottom.
And I notice that when we get attacked by them,
our performance drops dramatically.
So I'll switch to our FPS performance gauge
so that we can see our performance live while
And you can see on the right here we indicate
to you your target frame time.
And in our case, it's 16.6 milliseconds, which corresponds
to maintaining a frame rate of 60 frames per second.
We can also see that a good amount
of our time is spent rendering,
as well as running our client update,
and we've got a good amount of wiggle room of CPU idle time.
So I'll go into our game and move to the right here
where we have an enemy robot, and I'll let him hit me
so that we can try to reproduce this performance issue.
So now I'll switch back to our performance gauge
to see what's going on within our update loop.
And I'm noticing that quite a bit
of time is spent evaluating actions.
In fact, now our frame rate is dropping quite dramatically.
So I'll go ahead and pause our app
so that we can take a closer look at what's going on.
Now that we're paused, I can scroll back in time
within our frame breakdown
to see our frame time previously within our app.
In fact, here we can see the time that we were
in the main menu where we spent a little bit of time rendering
but most of it was spent idle,
as well as the breakdown we were seeing within our game.
And now when we are seeing performance issues, I can click
and hold to examine details
for the performance issue we were seeing.
Here, I see we're getting 36.2 millisecond frame time,
and 71% of that is spent evaluating actions.
So what that tells me is there may be one
of two issues present within our game.
We could have a single action
within our scene that's taking an exceedingly large amount
of time to evaluate, or we could have a large number
of actions that's bottlenecking our update loop.
So now I know where within our update loop we're having issues.
So we've seen how we can use the State Machine Quick Look
to debug an issue we were seeing within our game,
as well as how the FPS performance gauge can show us
where exactly within our update loop we're having issues.
I'd like to now invite up Daniel Delwood
who will show you a new memory graph debugger that we can use
to determine where our issue with actions originates
from so we can fix it.
Thank you, Tyler.
So I'm very excited to tell you
about the new memory graph debugger in Xcode 8.
And like the view debugger,
it's a tool for understanding your applications better.
So just as the view debugger understands your view hierarchy,
the memory graph debugger helps you understand your memory
and how it's referencing each other.
The core question though that it's trying to answer is -
why does a certain object still exist on your heap?
Now objects reference each other.
And, you know, this is more and more a question of references
and annotation these days
in an automatic reference-guiding world.
So where can we go from having this problem of objects
that we don't want, objects that are leaked, or abandoned?
Well, there's some command-line tools
that can help, such as Heap.
And what Heap does is it snapshots your process,
looks through it for a summary of the different types
and the counts of objects that are in your process.
And you can even use the "addresses" flag to look
for a specific type of object
and get a list of those instances.
Once you have an instance you're interested in,
leaks is where you go for the connectivity kind
of information of, well, is it unreferenced?
Is it leaked?
Or is there some path from a global location
in your application that goes all the way down to your object?
Now, at any point in this investigation,
you might need some further detail,
such as the allocation stack trace.
And, that, you can get with malloc-history.
And this is all not a very visual experience,
and that's why we pulled all of these three tools into the IDE
for the memory graph debugger.
And so just a quick overview of, you know, how this is laid out.
On the left, the Navigator is where you get that heap-type
of information to start your analysis.
The center editor area is
where the connectivity information gets presented.
And on the right -- that's what we're showing you now --
the allocation stack trace via the Inspector.
So with that, I'd just like to jump right back into the demo
where Tyler left off and see if we can take a look
at those action problems that he was seeing.
So here we are with the FPS performance gauge, looking at,
you know, actions that are probably
at fault here in our application.
So I'm just going to jump right
in by choosing the Memory Graph Debugger button
in the Debug Menu Bar.
And on the left here,
the Navigator shows me my application with all
of the different types that are allocated in it.
And so they're broken down by a hierarchy
of module and then type.
And then under each of these, there's an instance.
And so, in this case, I'm kind
of interested in searching my heap.
And it's very easy to do.
I can just type into the filter, and I'll look for actions.
So here we are.
We've got types in SpriteKit.
And we see that, yeah, we have a lot of actions -- 559.
So it's probably that we have too many actions and not
that we have some long-running single actions.
So let me select one of these objects.
And the editor changes to show me the answer to the question
of why this object is still around.
In this case, it's showing me a root analysis graph
which allows me to trace the object I've selected back
to the left, back to the roots of my application.
So I can see that it's referenced
by an SKC sequence by repeat.
There's an array holding onto this.
And I can even disclose further to see
that here we've got an SKNode with some actions.
So, OK, it's part of this SKNode actions list.
I can click on this and try Quick Looking it.
If I want to take some more looks at this action,
I can select it and pull in the Inspector.
Now the Inspector shows me some memory details,
such as the class name, the address, the hierarchy
if it is a sub-class of some other objects.
What I'm interested in is where this action was created
so I can jump to there.
I can go ahead and collapse this stack trace and jump to my code.
And here, we see I've got this function -- refreshHurtAction.
All right, so it's running a HurtAction.
I can use the Quick Help to see that this action is added
to the list of actions on the node.
But I actually wanted to only have a single-player action
and make sure that this was replacing my previous actions.
So it's a pretty simple fix.
I'm just going to use the withKey variant here
and replace the player action.
And the Quick Help will show me that, yes,
this is actually the one I was wanting.
If an action using the same key is already running,
it is removed before the action is added.
Great. So that's a pretty simple way to jump to an investigation
about a specific type.
But one of the other things I noticed
when I hit the Memory Graph Debugging button is
that the Runtime Issues Navigator alerted me
to some issues.
So I can click on that.
And now I'm taken to the new Runtime Issues Navigator
which has a bunch of leaks that were reported in my application.
So I'll start out with a type that is defined in my module --
say, this LoadSceneOperation.
If I select it, now the graph isn't showing me
that same style.
It's showing me a reference cycle,
which is because this is a leaked object.
It's not reachable from those locations in my application.
And I need to find out what objects
in the leaked set are referencing each other.
So looking at this quickly, I have an operation
with some internal state.
It's referencing a completion block.
And then this has some captures as part of that block
that strongly referenced my LoadSceneOperation.
So if I click on the block, I can see the back trace
and go immediately there.
And here we are --
my LoadSceneOperation completion block.
I'm even using a capture list for "unowned self".
But the graph showed me that "self" wasn't the problem.
It was the LoadSceneOperation capturing itself right there
within the block.
So it's a pretty easy fix to make.
I just need to capture it unowned
and I can get going again.
But, unfortunately, that's not quite the solution here.
Because, since it's a completion block,
my LoadSceneOperation is just about done.
And so once it executes this block here,
the LoadSceneOperation is going to end its lifecycle
and it won't be around for much longer.
This means that when I dispatch async back to the main queue,
this LoadSceneOperation may no longer be valid
and I'm going to get a crash.
So it just goes to show that these captures can be tricky
at times and require a little bit of investigation.
And hopefully the memory graph debugger will help you
in your investigations as well.
So, let's talk a little bit more
about leaked and abandoned memory.
The memory graph debugger is a debugger mode, and so it pauses
to inspect your target application.
This is so your application doesn't keep going
and changing its state, and you can get a consistent view
of the world.
It also lets you do things like Quick Look
or PO different objects as you go through your investigation,
and it's available on all of our platforms.
Now, as I showed in the demo,
there's two different graph styles.
And the first one is that root paths graph style
which shows you for referenced memory --
maybe you've abandoned it --
how are different roots in your application like globals
and currently-running threads referencing that memory.
Now with the progressive disclosure model,
it lets you work back from your objecst
to different intermediate objects and find the reference
that should no longer be there.
For unreferenced memory or leaked memory,
that's when you see the cycles view.
And the goal there is to help show you what is strongly
And it'll let you figure out, again, a reference problem.
So, for stack logging integration that you saw
in the Inspector, it's not quite free to record all
of the mallocs and frees in your application.
And so this is a diagnostic that you'll need to opt into.
Just going to the Scheme Editor and selecting MallocStackLogging
in the Diagnostics Tab is enough to enable it.
And it will record, again, all of the mallocs and frees to disk
so you can look them up later.
But for memory graph debugging, you don't really need all
of the malloc and frees.
And previous lifetimes
of a malloc block just aren't usually that useful.
So, new in our current OSs is a Live Allocations Only Mode.
And so this has a lower overhead, and it also allows you
to get this rich information while you're memory
So this will set the "lite" flag to MallocStackLogging
in target environment.
So one other thing that you may enjoy
about memory graph debugging is
that we've introduced a .memgraph file format.
Now, sometimes you'll be debugging an issue
and you won't have the time to really dive into it.
And so you may want to save this off or have other engineers
on your team take a look as well.
So, from Xcode, you can actually go to the File menu
and select Export Memory Graph.
And what it'll do is save out all
of the connectivity information and heap information,
as well as some VM statistics
about your application to a file.
Then at some later time, you can just double-click,
load that file in the Xcode, and take a look at the memory graph.
Now this does mean that there's no process in the debugger.
So you can't get back traces, or Quick Look or PO the objects.
But it's still a very powerful technique
for an app analyzing after the fact.
Now if you want to build this
into your continuous integration,
we've actually got some options from the command line.
So you can just run leaks-outputGraph, pick a path,
and save out a .memgraph file for later.
So leaks, vmmap, and heap have all been enhanced to read this.
All right, now the fun part.
Let's talk about some usage tips here because this is all built
on the leaks infrastructure.
Now what this means is the graph is conservative.
We're trying very, very hard not to report things
as leaked when they're not.
And so in that attempt to avoid false positives,
there may be some extraneous references
that you see in the graph.
Now these references will show up gray for being unknown.
They may be valid references, they may not.
We may not just have metadata available to the tool.
And so take them with a grain of salt
as you're reading these graphs.
Now one thing you can do to improve the accuracy is
to enable Malloc Scribble,
which is another diagnostic in this scheme.
And this will mean that when allocation are free,
it will write over the memory so that you don't have
that uninitialized memory in that new block.
So for references that are known to be strong, these will show
up as bold in the graph.
And Swift 3 actually has a lot more reflection
And so I encourage you to use this
because it definitely is a lot more accurate in terms
of understanding captures and references.
And finally, I should put
out that the memory graph debugger requires
that you temporarily turn off sanitizers
like Address Sanitizer or Thread Sanitizer.
So this is a lot of information.
Where is a great place to get started with your application?
Well, validate your expectations.
Are there more objects of a certain type than you expect?
Are objects being deallocated when you expect?
Are there any leaks in your types as well?
Once you find an object that you're interested
in investigating, then the goal is to find a path
that shouldn't be there holding onto your object.
And two very common patterns
that you'll find are strong captures from blocks
and closures, or potentially even references upward
in your graph that need to be marked as "weak" or "unowned".
So, that's a lot of information.
But I just want to thank you very much for listening
to our information about new
and improved visual tools in Xcode 8.
We're really excited about things
like the better visual debugging with the view debugger,
with FPS gauge, and memory graph debugging.
So go out, try them out in your app today,
and solve a lot of issues.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.