I'd like to mention a trick I use often while debugging, a trick I learned from my good friend Markos Charatzas: triggering a sound when a breakpoint is hit. It's a pretty simple but useful trick, especially if you're debugging repeatable actions and you want to know when they happen.
I'm talking about this:
Sound Debugging - Markos Charatzas from NSConference on Vimeo.
If you don't have 11 minutes to watch the video (but please do, it's interesting!), here's short recap.
When setting a breakpoint in Xcode, you can set a number of options on the breakpoint:
the condition: an expression which is evaluated each time the breakpoint is hit; when the expression yields a truthy value, the breakpoint is actually hit. If it returns falsy, it's like nothing has happened.
**Ignore((: the number of times the breakpoint should be ignored. This is useful when I know the code in a loop goes ok for let's say the first 100 times, but fails the 101st or 102nd time. You can set a breakpoint before the offending line of code, have it ignored 100 times and then trigger the 101st time. Saves you a lot of "continue"s.
Action: you can add one or more actions to the breakpoint. You've got the following options:
- run an apple script
- capture a GPU frame
- run an LLDB command
- Log a message to the console
- run a shell command
- play a sound
finally, you can specify if the breakpoint automatically continues after it has evaluated all the actions. If you don't have any actions, this is a rather silly option since nothing will happen, but it's very useful when you do specify actions.
The ones I used most are
run an LLDB command,
log a message and
play a sound. The first two are pretty handy for adding ad-hoc logging to you app. No need to add manual
print() statements: you can just log from a breakpoint you can set on the fly.
play a sound. There's a number of sounds you can choose from:
When setting a sound action, it does exactly what you'd expect: it plays the sound you selected. Some of the sounds are long, some are short. There's one little caveat: it blocks your program while it plays the sound! So depending on where you place the sound, this action can have a serious "performance" impact on your app. That's why I usually go for short sounds (Morse, Tink, Bottle, Frog, Pop) for breakpoints which tend to get hit pretty frequently, and longer ones for "once in a while" breakpoints.
The cool thing about this technique is that you can actually hear what your code is doing (much to annoyance of your coworkers, so put headphones one when using this). If some concurrent code is not doing what you are expecting it to do, place some sound breakpoints in strategically placed locations in your code and you can just hear what is happening. If you don't get the sound pattern you expected, something is not going how you planned it and you can investigate further from there (with more information, because you do know now how the order of execution is). You can also log this to the console (remember, you can have more than 1 action per breakpoint) for later introspection, but I've found that the listening and analysing the music you code plays is a very valuable debugging technique.
I usually have one or more sound breakpoints in my concurrent "backend" code (when a network requests returns, for example, or after a long calculation), and then another one (or more) in UI facing code, so that you know that background piece of code has it's effect on the UI.
Or you can set it in any view related code, for example in the
-viewDidLayoutSubviews to know when what happens.
Like I said, it's a very useful technique since it allows you to use another sensory trigger to gather information, which is always a good thing.
Let's just hope Apple doesn't add a smell action to that list. 😳