This week, a WWDC talk about debugging in XCode is making me rethink some things.
So I decided to write about it. It’ll be a three part series:
- An outline of the techniques demonstrated in the talk (this post)
- How the talk challenged my views both on XCode and on learning a new stack
- Additional XCode debugging features not covered in the talk
Thank you to the talk hosts, Chris Miles and Sebastian Fischer, for unwittingly enabling this tangent 😃.
Here‘s where Apple keeps the video of the talk:
At that link, you can also:
- Get a transcript of the talk
- Download an HD version of the video (the low-resolution version embedded on the site itself makes it hard to read the text in the IDE)
- The slides (They don’t use these in the presentation, opting instead for live demos, which I think is more clear. But, if you like, the slides are there).
Outline: What the Talk Covers, in Pictures
We can set a Debug tab in the tab bar in the “Pauses” section of “Edit Behaviors.”
Here’s how you get to that:
Immediately after this, Chris demonstrates the elements of debugging in XCode that I see developers use the most often: setting a breakpoint (by clicking on a line of code), and printing out a value (by typing
po [value] after the
(lldb) prompt in the console).
Then we get fancy.
We can inject a line of code while paused at a breakpoint.
(lldb) expression self.view.backgroundColor = .green
We can also automate the injection of a line of code at a breakpoint without changing the code itself:
right-click breakpoint —> “Edit Breakpoint”, then
We don’t need to know a specific line to set a breakpoint if we know which method we’d like to inspect at runtime.
Here’s how we add a symbolic breakpoint:
We then type in the method’s caller and name. This one is in Objective-C because it refers to a method happening in the Objective-C code of UIKit.
Once we pause, LLDB offers us pseudo-registers to access information about that call of the method.
(lldb) $arg1 —> UINavigationBar <[Some memory address]> (the selector)
(lldb) $arg2 —> backgroundImage: (the argument label)
(lldb) $arg3 —> UIImage <[Some memory address]> (the first parameter)
We can set a condition under which we’d like a breakpoint to be triggered.
We can set a breakpoint to only be triggered once and be removed for subsequent calls on this line:
We can use a breakpoint to skip a line of code.
There are a few ways to print output from LLDB…
And if we don’t like those, we can implement our own:
We make our own debug descriptions by having the objects conform to the
CustomDebugStringConvertible protocol, like so:
We can also set watch points to be notified when specific variables’ values are changed:
And we can review our watchpoints in the debugging menu:
We can print the values of Objective C objects.
We can set aliases for LLDB Commands.
(lldb) command alias printobjc expression -l objc -O --
And we can even import a file full of LLDB aliases to customize our debugging command repertoire.
If we’re messing with views in the debugger and they’re not updating, we can force XCode to update the iOS frame buffer.
Chris then aliases this command to the 🚽 emoji, because no tech talk is complete without toilet humor, I guess. To be fair, I have also included a toilet reference in a talk before.
When the app is running in a simulator, we can debug the view hierarchy in XCode.
If we have an alert controller showing when we debug the view hierarchy, that will appear on the hierarchy as well:
We can also look at constraints…
…and set constraints to different values in LLDB:
(lldb) e [[(NSLayoutConstraint *) 0x7654f43) setConstant -30]
(The “e” in the above example aliases to “expression”.)
We can edit the scheme to log malloc stacks for all objects.
We can enable environment overrides while our app is presented in the simulator.
This allows us to see how our UI responds to different view modes (like dark and light) as well as different accessibility features like dynamic types (for increasing font size), button shape (for making tap targets easier to reach), and reduce motion (for making the app run faster or mitigating animations that trigger epilepsy—sidenote, please do not put animations in your app that trigger epilepsy).
I also inverted the colors for this screenshot because it makes the angry bird look somehow even more enraged, which makes me laugh.
Pretty cool, right?
Maybe learning about one of the features listed above has prompted you to open up XCode and try it for yourself, or even watch the original talk. Here’s the first part of a fantastic three-part tutorial, with starter code for both Objective-C and Swift, in case you want to dive deeper. Props to Fady Derias for that.
And while I highly recommend the talk, I also think this outline will be the least informative of the three pieces I’ll be publishing in this series. In the next post, we’ll talk about how these features fit into the broader cultural context of XCode users and how this talk has informed some changes in my approach to learning a new programming language or stack.
If you liked this piece, you might also like:
The Leveling Up Series (a perpetual favorite for gearheads like yourself)
The Books Category, to which I’m slowly adding all the blog posts where I reflected on a book
The History of API Design Series (prepare to have your sacred cows threatened)