Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2011-319
$eventId
ID of event: wwdc2011
$eventContentId
ID of session without event part: 319
$eventShortId
Shortened ID of event: wwdc11
$year
Year of session: 2011
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2011] [Session 319] Effective D...

WWDC11 • Session 319

Effective Debugging with Xcode 4

Developer Tools • iOS, OS X • 55:13

Xcode 4 introduces a refined and powerful new debugging interface. Discover how you can better track the value of your variables, better debug multithreaded applications, and find and fix issues faster than ever. Join the Xcode engineering team for an in-depth look at the Xcode debugger and LLDB.

Speakers: Anders Bertelrud, Blake Chaffin, Ken Orr

Unlisted on Apple Developer site

Downloads from Apple

HD Video (1.33 GB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

So this morning I'd like to start with a question. How many people here are using Xcode 4 100% of the time now? Oh, good. I was hoping to see everybody's hands go up. And how many people are new to Xcode in general this past year? So you've been using Xcode for less than a year? A fair number of people. Great.

Whether you're new to Xcode or whether you're a veteran developer, the chances are that we all use the tool in a different way. But Xcode was designed to fit a whole variety of working styles. And if you take the time to configure Xcode to work the way that you work, it will make you more effective as a developer, and it will also make you more productive in your day-to-day work. And so what I'd like to do today is to show you some of the things we've done in Xcode 4 that I think will make you more effective and productive in your day-to-day debugging tasks.

So the first part of being effective with debugging in Xcode is to understand the fundamentals. So let's take a second and look at the fundamentals of debugging with Xcode 4. Now, before we even run our application for the very first time, there are some settings that we might want to change that will affect the way that we run.

And you do that in Xcode through the schemes. So the schemes have a whole variety of settings. And you can view these schemes by pressing Command-less-than or by option-clicking on the Run button. And when I do that, you'll see that the scheme sheet slides down. And you'll notice on the left, there's a whole bunch of actions. So that's build, run, test. Those are all scheme actions.

Now, the one we care about that pertains to running is obviously the run action. So we're going to look at that. So the Info tab has sort of the main settings, the most important ones that we will likely want to tweak and change. And the first one of those is the build configuration. So this lets you change whether you build with debug symbols or not. So 99% of the time when you run, you're probably debugging and you want these debug symbols, but you can change that to release. if you'd like.

Now, the next option here gives us the ability to change the executable that is run when we press the Run button. So why might we want to do that? Well, if you're working on a framework and you want to test your framework out against a particular application, you can choose that application right here.

The third option is probably the most important option, and that's the ability to switch debuggers. So you can select the LLDB debugger, which I encourage you all to do. That's Apple's new, faster, better, stronger debugger. And in fact, they have -- the LLDB team has a talk right after this one, and you should check that out. So if you can, try to use LLDB in your day-to-day debugging tasks and see how that works for you.

As we move down to the last option here, this gives us the ability to change the way that we launch. So by default, and this is the way you'll probably want it most of the time, Xcode will automatically start your app for you. So when you press run, everything will just launch up, and you'll be ready to debug. But that's not always what you want.

Sometimes there are issues early in the launch cycle of your application, and it turns out you might want to manually launch your application. Now, you might do that from the Finder, or if you're iOS, you would do that from the launch screen of the iPhone or iPad. And when you select wait for my application to launch, Xcode will get ready to start debugging, but it will then start looking for your application to be launched, and it'll wait for you to do that. So that's a handy setting. If it turns out that you need it.

Okay, let's slide over to the next tab. This is the arguments tab. So here, obviously enough, we can set arguments or add arguments to pass in to our application. We can also set environment variables that we want to use. Now, one nice feature of arguments and environment variables, or one powerful feature, is that we can actually use build settings that will get automatically expanded for us at runtime.

So this base expansions on popup, you say, what is that? That is basically saying I want my build settings to expand using this target. So in this simple case, we're looking at Sketch. Very simple. It only has one target, which is why this popup is disabled, so there's only one thing to expand against. When we use a build setting, like in this case, I'm using built_products_dir, at runtime, this will be the target. This will be expanded out to the build directory of Sketch.

So this is a powerful way to get at the build settings into your arguments and environment variables. Okay, so as we slide to the next tab here, this is the options tab. You'll find all of the platform and OS specific settings in this particular tab. So this is sort of a dynamic tab. You have some dynamic options here.

Now, in this case, we have a Mac OS template. We have a Mac OS X.7 application. So you'll see that we have this new persistent state option. So that lets us enable and disable the resume feature. Sometimes you want to turn that on and off as you're debugging. And because it's a desktop app, we also have the ability to set the current working directory. Now, if we were looking at an iOS app, we would have some different settings here. Let's take a look at what those are. So in iOS 5, we have the ability to simulate our location. So we can choose that location right here from the scheme.

And we can also choose what application data that we want to run with. And if you were linking against the OpenGL ES framework, then you could actually turn on and off the OpenGL ES debugger right from here. Okay, so we've set all the settings, we've tweaked everything, now we're actually ready to run, so let's do that. Now you can see that in this particular case, I set a breakpoint because that's where I want to stop.

So let's actually start the app now. And we do that, of course, by pressing the run button, which is in the top left of the toolbar. Now when we do that, Xcode will start our application up, and then in this case, it's hit a breakpoint, so that pauses execution, and then you'll see that Xcode has inserted the instruction pointer, that's that green highlight, so that tells us where execution is paused right now.

So you'll also notice that there's a couple of other things that Xcode has done for us now that we've paused and we're ready to debug. So the first thing is it has shown us the debug navigator. Now, the debug navigator is one of seven navigators in Xcode 4, and it shows you the current process, the current threads, and stack frames. And you can select between those and jump around.

Now as we move to the right, to the editor area, as far as debugging goes, there's a couple interesting things here. So now that we're running and that there's some information available, we can do things like mouse over a variable. So here I'm mousing over self, and when I do that, Xcode shows me a data tip with self's value. And I can twist that open and inspect that. One other really useful feature that you can access right from the editor is via the context menu on the gutter.

So if I control click in the gutter here where the line numbers are, Then you'll see I'm offered these options, one of which is continue to hear. So when is this useful? Well, if you're debugging along and say you run into a for loop that's going to iterate through something 10,000 times, well, of course, you don't want to step through that.

So you can control click on the line right after that for loop, and you can say continue to hear. And that's a really nice, easy way to resume execution and then pause again without having to use breakpoints or anything. In general, in Xcode 4, I would encourage you to check out the context menus. There's a lot of functionality that's behind them. So if you're looking for something or if you're just curious, take a look through there and see what's offered in the context menus.

So as we move down to the bottom of the screen here now, we see the debug bar has popped into view. So the debug bar offers our resume control, so when we're done debugging and we're ready to resume the application, we press the resume button and, of course, the stepping control so we can step through our code. That's all through the debug bar. There's also a readout of the current process thread and stack frame right from the debug bar.

And then also you'll notice on the very far left is the show debug area button. Now you can also press Command-Shift-Y, and when we do that, we'll see that the debug area slides into view. So the debug area has two more really important views for our debugging tasks, the first of which is the variables view. So the variables view shows us the variables at the current stack frame that were stopped at.

So we can inspect their values, and as we step through our code, we'll notice that in the variables view, the values are updated and we'll see the values that have changed highlighted in blue. So it's a really nice, easy way to track values changing as you step through your code. Then if we slide to the right here, we'll see the console.

So the console is our direct line of communication with a debugger, and it also shows us the printouts. So as we put NSLogs in our code, we can see that the values are updated. They're shown via the console. So when you need to interact with the console, this is where you can do that.

Now, while I have the variables view up here, I want to show you its context menu. Because I told you there's so much functionality there, and I'm going to prove that. So a couple of the really useful features here that I want to point out. The first and probably most useful one is the ability to just print the variable out. So that's most of the time you just want to see the value of a variable. You can do that right through the context menu.

You can also change the way you're viewing a variable. So if you want to view it as an int, hex, there's a variety of other things you can view it as. You can change the natural way you're looking at it through the context menu. Then this one is really probably the most powerful one up here, and that's the ability to watch a variable.

So when would you need this? Well, sometimes a variable is changed out from underneath you. So its value just changes, and you don't know who is changing it or when it's getting changed. Well, if you set a watch point on that variable, we'll insert something like a breakpoint.

And when the value of that variable changes, we'll pause execution and we'll take you to the line of code that caused that variable's value to change. So this is a really powerful way to track down those values changing out from underneath you. And then finally here, you can view the memory of a particular variable. And when you select this item, we'll open up the memory browser right in the main editor area there for you. And then you can inspect and page through the memory.

And then finally here, the last bit of UI that we're going to need in our day-to-day debugging tasks is the breakpoint navigator. So the breakpoint navigator shows us all the breakpoints in a nice, neat list that are set in our workspace. And we can do things like enable and disable them by clicking on that little blue breakpoint icon. We can also delete breakpoints by just dragging them out of the breakpoint navigator. And then we can edit the breakpoints.

So some of the things you can change about a breakpoint are, for example, its condition. So if you want to control when a breakpoint is stopped at, you can set an expression in its condition area. So when that expression evaluates to true, we'll stop at the breakpoint. When it evaluates to false, we won't.

The next option here is an ignore count. This is particularly useful if you're doing event-driven debugging. So anytime you're doing anything with mouse events or drawing to the screen, you may want to ignore a large number of cycles through your code. As you're moving the mouse around, you don't want the breakpoint to be hit. So you can set an ignore count, you know, 25, 50, whatever it is, and we'll ignore that breakpoint until the threshold is exceeded.

Now onto the most powerful thing you can do with the breakpoints is you can actually add actions. So actions let you do things like play a sound. So when a breakpoint is hit, you can play a sound. But one of the most useful things you can do, one of the most useful actions, is the ability to execute commands via the debugger console. So you can actually print out the value of a variable right from here using a breakpoint action.

Now, when you combine that with the next option, this automatically continue, by itself, the automatically continue isn't really that useful because we're not going to stop at the breakpoint. But if you select automatically continue and say you print out the value of a variable, then essentially what you're doing is you're inserting NS log statements into your code without actually changing your code.

So there's no recompiling. You can do this all while you're running. And, of course, the best thing is that you're not going to be checking in unnecessary NS log statements into source control. So this is a really great way to quickly iterate when you're debugging. And I do this all the time.

All right, so now we understand the fundamentals, but to really make ourselves effective with Xcode, we need to make it match the way we want to work. So let's talk about doing that. To illustrate that, I want to show you this example here. A lot of people have asked, how do I show a console in a separate window? One of the first things people asked.

And it's very, very easy in Xcode 4. You just have to understand the way in which you tweak the UI. So that's all done through name tabs. So just like in Safari, you can create tabs in Xcode, and you do that by pressing Command-T. And when we do that, we see a new tab shows up. But unlike Safari, these tabs, well, first of all, you can name them. So you can name them something meaningful to you. But they're also very, very stateful.

So as you show and hide various bits of the UI, or as you drag them out and you resize them, reposition them on different monitors, all of that is persisted across launches of Xcode. So you can set Xcode up to look exactly how you want and quit and relaunch, and it will remain that way.

So in this case, I created a new tab, and I'm going to name it console because I'm just going to show the console here. So now what I'm going to do is I'm going to hide the navigator area. Don't worry, if you don't catch all this, we're going to show you a demo in a minute.

I'm going to drag the debug bar all the way up to the top so we hide the editor area. And then I'm going to hide the variables view. So now all we see is the console. So far, so good. All we need to do is drag out that tab into its own window. And now we have a console and a separate window. I can move it to another monitor, quit, restart Xcode. I can see my source code, debug navigator, console, everything at once. So this is a really nice way to configure the UI to match the way you're working.

Now that's great, but it gets even more powerful when you combine name tabs with behaviors. So what are behaviors? Well, behaviors are a way that you can control what Xcode does when certain things occur. So, for example, when a build succeeds, you can have Xcode play a sound and maybe bounce the dock to give you auditory and visual feedback that the build has completed successfully. Now, if a build failed, maybe you want to play a different sound. So this is your way to control Xcode's interaction with you.

As far as debugging goes, as I mentioned earlier, one of the default behaviors is when you pause, so when you hit a breakpoint, Xcode will show you the debug navigator. Why does it do that? Well, the goal here is to minimize the amount of work that you have to do in configuring the UI to get where you need to be. So the thought is when you hit a breakpoint, you need to debug, so you probably need to see the debug navigator to do that.

Now, of course, if that's not the way you work, it's not a problem. That's why we have this highly customizable behaviors panel here. You can tweak a whole lot of things. So if it doesn't match your working style, I encourage you to go change the way it does work. And here to give you a demo of name tabs and behaviors in Xcode 4 is Blake.

Thank you, Ken. So we've heard about some pretty powerful features to help you customize your workflow. Let's take a look at a couple of them in action. So by default, without changing anything, I'm gonna start a debug session and see what happens. Building Sketch. We can see as we hit this breakpoint, the debug navigator on the left has been shown, and the debug area at the bottom has been shown automatically.

You can see on the left side we've got the variables view. I can inspect objects with the disclosure arrows. I can see what's inside the object, or if it's a union or struct, I can see the fields there. And I can even change the values if I like.

And over on the right side here, we've got the debugger console. This is where I can interact directly with GDB or LLDB. If you're familiar with Visual Studio, the debugger console, you can think of it similar to the immediate window and the output window combined, only more powerful.

So that's nice, but how did we get that for free? Well, if I go to preferences, You can take a look at the Behaviors tab, and by default, you see that when a run pauses, we're going to show the debug navigator, which is the navigator on the left, and we're going to show the debugger area on the bottom.

Some enclosed preferences. So that's nice. We get that for free. But what happens if I stop the debug session? I've still got the debug navigator on the left. I've still got the debugger area on the bottom, but we're not debugging anymore. I can switch back to the project navigator and I can hide the debug area, but Why don't we make that automatic? So go back to preferences, back to behaviors. We can see there's a trigger for when a run completes.

We can say, what do we want to do? Maybe I want to show the project navigator. All right. Maybe I want to hide-- The debugger. So with those two changes, let's have a look again. If I run one more debug session, So we saw we switched from the project navigator to the debug navigator.

Even though we had the debug area closed, it came back up because that's what we've told it to do. And now if I stop the debug session, either with the stop button in the toolbar or by simply quitting the app, we see that we now have the project navigator and the debug area went away.

Pretty nice, but maybe, I personally like to work this way, but it might be a little jarring to have one window constantly changing state every time you go into a debug session and you come back out of it. So let's make a new tab. As Ken mentioned, I think it's Command-T, same as Safari.

I'm going to name this tab by double-clicking on the name. I'm going to call this Debug. So we now have a tab called Debug. When we make it, it looks exactly the same as the previous tab we had open. But if I go back to preferences, we're gonna see a lot of preferences.

Slow Mouse. So I can say when a run pauses, say when we hit a breakpoint, these are the default settings. We show the debug navigator, we show the debug area at the bottom. I'm going to add to that, I'm going to say show the debug tab. So show tab, tell Xcode which tab you want to show. It's the one we call debug. Going to close preferences. Go back to the main tab. One more debug session here.

And we see that the debug tab has come frontmost. We've got the debug navigator and the debug area. And as soon as we stop, we can go right back to the main tab and It's mostly the way we left it. So that's a bit more helpful. Maybe if you want to persist some state, if you wanted to interact directly with GDB and print out something complex and then have it to go back later and refer to, you can have different tabs.

But it doesn't stop there. How many people use multiple windows, or multiple monitors, rather? Maybe you want to have more than one window. Oh, yeah, I do too. How many people like to interact directly with GDB or LLDB? And they just want the UI to get out of the way. Yeah, yeah. All right, so I'm going to make another tab. Command-T, same as Safari. I'm going to call this one Console.

This is my favorite part of the demo. I'm going to pull this out into its own window. We're going to hide the navigator. Going to show the debug area. These are all with the buttons in the toolbar at the top right. I'm going to pull the debug area all the way to the top.

I'm going to use the buttons in the debug bar to hide the variables view. And just to get those last few pixels, I'm going to Control-click the title bar and get rid of the toolbar altogether. Now we've got pretty much a full screen console window. Make this big. I'm going to make my workspace window just a bit smaller, get some real estate here. So now we're starting to look like a proper Unix debugging environment.

A nice trick, I'm actually going to close the console window. Sounds crazy, but stay with it. I'm going to say that when a run generates output, say if you've got a log statement, I want to show the tab called console. If I can get the mouse to cooperate.

So we're going to show the console tab. And we're not going to show the debugger. We're just going to bring it up as is. I'm going to disable this breakpoint. Now if I run one more time, either Command-R or the Run button in the toolbar, Since we have some, I logged that my window was loaded, so the debug console window, even though the window was closed, it comes back up, it's the way we configured it, and now I can interact directly with the debugger. If I pause the debugger, that is.

So we stopped at a breakpoint. The behaviors say, show the debug tab, show that navigator, show the debug area. So you can see the behaviors really doing stuff automatically for me. In this case, I was going to show that I can print object, self-- oh, no, I'm in main. There's no main. There's no self in main.

Well, if there were objects, we could print them there. So I'm now interacting directly with GDB or LLDB, as the case may be. and that is behaviors and tabs and windows. So we've seen that with behaviors, named tabs, and even separate windows, Xcode 4 gives you tremendous flexibility to customize your debugging workflow. And with that, back to Ken.

Thanks, Blake. Some good stuff there. Okay, this next thing that I want to show you is a feature aimed squarely at making you more productive. So there's a lot of great UIs we've seen for debugging in Xcode 4, but there are times where you just need to interact with the console. Now, how many of you have variable names that look like this? It's okay. That's good. That's a good thing. Long descriptive variable names are good in your source code. Not so good when you have to interact with the console.

Now you might say, well, I can just copy and paste this from my source code into my console. Yeah, you could. You have to have that source code visible and scroll to the right spot. But you can do it. A little cumbersome, but it's doable. But now what if I want to print the result of a method like this? Copying and pasting isn't going to help me so much here. Now, maybe you could copy and paste it, and then you have to go to each argument, and maybe you have that long variable name again, and you have to type that out. So it's just not a really nice way to interact.

Wouldn't it be nice if Xcode could help us out a little bit here? Maybe you're saying, there's some great stuff in the source code editor that helps us out with typing quite a bit. Well, in Xcode 4, we've added full console completions, so we've taken that great engine we have... We've taken the fantastic engine we have in the source code editor, and it's that same engine that's feeding the completions to the console.

So I should also point out that it's very context sensitive. So when you're stopped at a breakpoint, we know exactly what file and line number you're stopped at. And the completions that you get are relative to that line in the code, just like if you were typing in the code at that line.

So of course we can get our variable completions, and we can also get method completions. So we get those nice little blue bubbles that we can tab between and delete and type over. And so I think this is my favorite feature, and it's a huge, huge time saver when you're dealing with a console.

So let's move on to another more workflow-related feature in Xcode 4. And that's the ability to debug multiple processes at the same time. So that's new in Xcode 4. The canonical example of this is when you have a client-server application. So you have a client, you have a server. You need to run them both at the same time because you need to, you're debugging the interaction between the two of them. So they have to be both running with potentially breakpoints in each one.

But it turns out that there's a much more general use case for this that really applies to probably everybody here. And that is this. So if we're running our application, and we're running along, and we bump into a bug, and maybe there was a lot of reproduction steps to get to the point where we could reproduce this bug, but we've done all that, and now it's happening every time.

And so we look through our code, we find what we think is an easy fix, and we want to make that fix, but we don't really want to stop the current process because, I don't know about you, but I like to be able to verify, okay, I can reproduce it here, and then I have a fixed case over here where it doesn't reproduce. So if I can see those both at the same time, reproduce bug, don't reproduce bug, then that makes me happy and makes me confident that I've actually fixed the problem.

So what we can do is we have our buggy copy running. Now we've fixed our code. We can press run again, and Xcode will say, "Well, you already have a process running. What do you want to do? Do you want to stop your current process?" Well, in this case, we don't want to do that. We want to add another copy, so we want to build and run the fixed copy. So we say add. And then we're going to run the next copy.

So we press add, and now we'll notice that the debug navigator shows us two processes. And to help us differentiate between the two, you can see that it's added the process identifier there for us. And so we have our buggy copy on top, and then we have our hopefully fixed copy on the bottom. So we can then go verify that we fixed it.

And to really help prove it to ourselves, we can go back to the buggy copy, do the exact right reproduction steps, go to the fixed copy. Do those reproduction steps. And this is a really nice way to help prove to yourself that you fixed something. And it turns out there's actually some other use cases for this as well. Not so much related to debugging, but if you're doing some animation, say.

Say you're sliding in a view, and you're debating, should we be using a quarter second, or should we be using a half second? Well, the best way to do this is to run both at the same time. Run one with the animation at a quarter second. And run a copy.

Run a copy with the animation at half a second. Otherwise, it can be very hard to evaluate them when they're not side by side. So that's another really nice use case that I use this for. Here to give us a demo of multiprocess debugging in action is Anders.

All right, so Ken gave a couple of examples of good use of multiprocess debugging. Another one is when you have an iOS app, and let's say you have a game that does some peer-to-peer networking for multiplayer gaming. One of the demos we saw in the developer tools kickoff session on Monday was a simple space game, Touch Fighter, and that game actually has some multiplayer capabilities.

So you can start a server game on one machine, an iPad, and then you can also go ahead and run the same game on a different iOS device and join the existing game and do multiplayer this way. So let's go ahead and take a look at that. Turns out there was a bug conveniently for the demo that involves sending the name of the device you want to connect to when you're trying to join a multiplayer game.

So to take a look at that, I'm going to go ahead and run for a second. So I'm going to go ahead and run the first on the device. So I have an iPad 2 here. And I'm going to go ahead and switch to the iPad, show you what's on the screen there.

[Transcript missing]

So here we go. It's launching on the iPad again. Looks just like the last time. Now I hit multiplayer, and I choose to host a game. And we see now that it's stopping at this breakpoint here. So, and meanwhile, if I go to the debug tab, you'll see we already have Touch Fighters running in the simulator.

A little bit hard to see here. But, and then the other instance is paused, and we see the breakpoint. So as I step over here, I'm going to go ahead and hover over the unique name, Ivar. And I can see here, if you look on the right side here, that we see the big long hex string, which is the identifier of the device, and the human readable name separated by a colon at the very end there.

So this says that the server, this is just an internal protocol that this game is using, and it's when it's advertising the Bonjour service. And then it says it's actually sending the human readable name of my iPad. So I know that the problem is on the client side, because the server is sending what I expect to do based on my coding.

So let me go ahead and resume then on the server side. And instead, I'm going to pause on the client side. What I'm going to go ahead and do here, let me go ahead and go to a breakpoint. I know my code well, so I know that the init with name address, init with name method is the one that gets called whenever I go to set up a new connection. I'm going to go ahead and start it again in the simulator. If the game had a way to go back and forth, I would just do that. So it's going in the simulator. Let me see here.

I'm going to go ahead and quit the simulator here and restart it. And now this time, I have multiplayer, I join a game, and I see that I break on the break point. And meanwhile, the game is running on the iPad as well. So now in this case, as I step through here, I can use the normal debugging techniques, looking, either hovering over a particular variable or opening up the debug area down here.

And in fact, if I take a look at this, I'll see that this length here, I'm taking the length, but that's supposed to be location. In this particular case, it's looking for the colon. I see the code completion kicking in. And then to verify that I fixed the problem, I'm just going to go ahead and run one more time in the simulator.

Multiplayer, I hit join a game, choose my spaceship, and now I can actually see, okay, I fixed my bug, now I can see the human readable name. So this is one way, just an example of how you can go back and forth between two instances of, in this case, a game that has multiplayer capabilities and see, well, what's the server sending, what is the client receiving, and you can really look at both of those. Of course, you could do this with two different machines, but it's a bit more convenient to do it in one copy of your source code on one machine.

And if you have multiple devices attached, let's say an iPod Touch and an iPad, you can run on each of the various devices and really have two or more, three or four instances running at the same time. So with that, a little demo, I want to hand back to Ken, and he's going to show you some other cool features in Xcode 4. Thank you, Ken.

Great. Thank you, Anders. So finally today, I'm excited to show you the new integrated OpenGL ES debugger in Xcode 4. So if you've ever written OpenGL code and you've had a bug that resulted in, say, a black screen, that's a pretty typical result of an OpenGL bug, you might not have any idea what to do.

Well, the new OpenGL ES debugger makes it much, much easier to debug these kinds of things visually rather than having to sprinkle printouts throughout your code. So let's take a look. So here I'm running my app, TouchFighter, which we've seen a bit this week. And you'll notice, since this is linking against OpenGL ES, and I've just started running, that this little camera icon pops into the debug bar. That's the frame capture button. So it says, when I press this, initiate a frame capture and capture all the OpenGL draw calls involved in a single frame of OpenGL.

Now, there's also another way to initiate that, and that's through a breakpoint. So we can set a breakpoint, and we can add an action and set that action to be the capture OpenGL frame action. So when Xcode hits that breakpoint, it will automatically initiate a frame capture for us.

Now, once that capture is complete, Xcode will show us the results. And here's what it'll look like. So in the main editor area there, you can see the frame buffer viewers. So here we have two frame buffers. We have the color one. That's the actual colors you'd see on your iPad or your iPhone. And then you have the depth buffer as well.

On the left side in the debug navigator, you'll notice that we're not seeing the normal threads and stacks any longer, but we're seeing all of the OpenGL draw calls used to generate this frame. Now, you'll also notice here, too, that those OpenGL draw calls are organized rather nicely into these little folders, these little yellow folders.

So the things that say stars, planet, mothership, those are marker groups that the developer actually inserted into their own code to help them logically group things and eventually help them debug. Now, you can add these yourself with these new functions. So you can call glPushGroupMarkerApple, and then you give it a name. Then you do all your drawings, all your OpenGL drawing, you do that.

And then you say glPopGroupMarkerApple. And that will be the name of the marker. And that will be the end of the folder. And, of course, you can nest these arbitrarily deep so you can have nested folders. And this gives you a lot of power to organize your draw calls so that you can see them nice and neatly in Xcode.

Okay, now when we slide open the debug area, we notice that we don't see the normal variables view and the console any longer. What we see are two variables views. And these variables views are showing us the OpenGL state. And just like in the normal variables view, we'll see values that have changed between the OpenGL draw calls in this case. When values change, we'll see those highlighted in blue. So it's easy to identify what's changing between draw calls. Useful, very useful in debugging. And now let's show the assistant.

So we show the assistant, and we can see all of the resources used to build up this frame. So resources are things like textures, shaders, all those things that are going into actually drawing the frame. And of course, you can double-click on any of these items to view it, to inspect it, maybe find defects if that's what you're looking for. In this case, it's an image, but some of them are matrices of numbers. But just know that you can see all of the resources right from the assistant view. And here to give us a demo of the OpenGL ES debugger and Xcode 4 is Anders.

Hello again. All right. So we're going to go ahead and stay with Touch Fighter. We fixed the network problem. Let's go ahead and run it on the device again. And you may recall that on Monday, one of my colleagues used the OpenGL ES debugger to diagnose and to fix a problem. And the -- let's go ahead and quit that. Hold on.

One of my colleagues used the OpenGL S debugger to find and fix a problem in the Touch Fighter drawing code. And that had to do with the spaceship and the wings on top of the spaceship. And now, since Monday, apparently somebody has gone and broken another part of it, because now one of the other spaceships is black. So when the device is up and running, let's go ahead and figure that out and see what's happening there.

I'm going to go ahead and reboot the device. Did I mention this is pre-release software? If you find any bugs, we would love for you to report that on Bug Reporter, and we'll be delighted to take a look at it. Meanwhile, let me go ahead and talk to you a little bit about how we would debug this without having the OpenGLS debugger.

One of the common things that you might do is to set -- to add log statements, to set breakpoints. If you've done OpenGLS debugging, one of the things that you know is that setting the state may actually affect what gets drawn later because it's very stateful. So OpenGL consists of a lot of set state calls followed by drawing calls. And so when -- and the drawing calls are the ones that actually cause the bits to get drawn on the screen.

So the way it basically works is there is a command stream. And you end up calling set state, set state, set state, upload this texture, upload this shader. And then you actually say, okay, now draw something for me. And so as Ken mentioned, you can insert markers and cause the objects to -- cause the draw calls to be grouped into statement -- into groups that are logical for your problem domain. So whether it's a game or scientific visualization or anything else like that.

And we also have added API in iOS 5 to let you label resources such as textures and shaders and give them human readable names. And these are no ops unless you are debugging. So they only show up while debugging, and they don't have any other performance costs at all.

So the device is booting here, and as soon as it's ready, we're going to try again. So let me show you meanwhile, if I go to the breakpoints, The way to set the breakpoint for, let's say we want to go into the code here that renders the mothership.

We see a whole bunch of draw elements calls. And if we edit the breakpoint, set a breakpoint here, and this is where we want to, we can actually run an AppleScript command, or we can capture an OpenGL frame. And I think my device is up and running, so I'm going to stop the ad libbing, and we'll see if we can do this again. All right, I'm going to select my device. I'm going to go ahead and run.

And as Touch Fighter is coming up, let me go ahead and switch to the screen. There we go. Nothing a reboot can't fix. All right. So I'm going to go ahead and choose single player mode this time. And darn it. Somebody's broken so that now the mothership is black.

Okay. Matthew fixed the upper wings. Can't go to a conference for a week without something breaking. But let's figure out what's going on, though. So again, we hit the OpenGL frame capture. And in this case, I'm going to go ahead now and switch to the screen. back to the Mac.

And we see that on my Mac, I'm seeing the exact thing that's shown on the iPad screen. And of course, this works with iPod Touch or iPhone as well. So as you've seen a couple times already, here's the render buffer. The frame buffer is actually the one that's shown on the device. And I can also see a depth buffer here. And this is a buffer that has an element corresponding to each pixel in the frame buffer, but it stores the depth value.

So this lets you do hidden surface removal or hidden pixel occlusion. And if we were using a stencil buffer, which is another OpenGL resource, then I could also see that here. This game doesn't make use of that. So that's why that's disabled. On the left here, as Ken told you, we have the various groups. We have all the draw calls, the entire command stream, all the state and draw calls, but they're grouped by the markers that I've added. And until you add markers, what you'll see is one long list of state and draw calls. But there can be tens of thousands.

So it's a good idea to add the markers. They don't cost anything when you're running outside of debugging. And they can be a real big help here. And as Ken mentioned, you can nest them. Here, for example, I see the enemies. And I can look down on each enemy ship.

And of course, if I choose a location, I go directly to where that's drawn. The green you see here is the wireframe of the actual triangles that were drawn. And when we're looking at something small, some very small triangles, the wireframe can take up almost the entire object. This means that each of the triangles contributed only a few pixels.

I can go ahead, by using the context menu, I can go ahead and hide the wireframe so I see what object is actually being drawn. So these are things you've probably seen before, but I'm going to go ahead and show some things that are hopefully new. Let's go ahead and hide the left area here by clicking here. And then I'm going to go ahead and open up the assistant view.

[Transcript missing]

And I'm pretty sure here that the problem is I didn't set my shader properly, just based on looking at this. So what I'll go ahead and do then is I'm actually going to open up a second assistant. I think Matthew might have shown you this on Monday as well, and it's actually one of my favorite ways of working too.

And then as I step through, it goes from element to element, and I can really see the source code and the bindings, and I can see the result on the frame buffer. And again, I can step backwards as well. Here we're back to where we were drawing the planet, and now here we're into where we're drawing the first part of the spaceship.

And if I look here at the, I can go ahead again and open up the left side, and what I can do, if I've gotten to a certain point, I can go ahead and open up the left side, and I can go ahead and open up the right side. And if I go to the point with the stepper controls, and I want to see where it is in the hierarchy, we also have the reveal in debug navigator command.

That can be really handy. So that takes me directly to the point in the hierarchy here where the command is set. So now as I look at where these calls are coming from, I think there's an issue with the render object. I'm going to go ahead and use our UI for putting the source code into a particular assistant editor, and I notice something here. It says unset open GL states.

But I actually forgot to do a set open GL states. This is not an API call, but it's a call in this particular program that sets up a whole bunch of things like the shader. So that looks promising. Let's go ahead and see if that actually fixes the problem. I'll switch back to the iPad.

What do you think? Is that it? Yeah, that fixed it. So in this way, I can go and take a look at is it the wrong texture? Is it the wrong shader? Did I set the wrong parameter? If you ever programmed OpenGL, you know that it's very easy to accidentally leave some attributes set or to forget to set some attribute. And then you go on to the very next piece of code that you're going to draw, and then it's all wrong. And so typically, the traditional debugging methods have been let me get the GL state for a whole bunch of parameters and print them out to console.

And then look at it after the fact. Or let me comment out the section of code. Like I would have commented out the planet here to see, oh, does that cause my mothership to draw correctly? If it is, I know that it's a sort of bleed over of state.

But we think that the OpenGL ES debugger is a much better way to do that because you can actually see the entire set of commands that went out into building up the OpenGL frame. So with that, I'd like to hand back to Ken. And thank you very much. Thank you very much.

Okay, so today we've shown you a number of things that I think will help make you more effective and productive in your day-to-day use of Xcode. If there's one thing that I could have you take away today, it's that Xcode is highly customizable. It's very easy to customize, and a great starting point is to start working with the behaviors. So I encourage you to go do that. With that, I thank you very much.