Xcode conditional break points

I've been developing for iOS for quite a while now and I'm always amazed at the things I don't know that can really change my workflow. I've felt at home in the debugger for a while - printing objects and scalar variables, assigning values and generally navigating around fairly smoothly. Today I got a new tool to put in my programming belt with the knowledge that it's possible to create conditional breakpoints - this is something that I wish I knew a long time ago.

Problem in context

It's a fairly common problem that you'll have an issue that occurs only while in some kind of loop, whether it is a for loop or a user interaction loop of some kind e.g. tapping a button multiple times. It can be both tedious and error prone trying to get yourself set up to examine state when you have to perform repetitious work like pressing continue on the debugger. It's easy to overshoot your assumed condition and have to start again or maybe it would just take far too long to get yourself in the correct state manually.

Meet conditional breakpoints

Our test scenario is both silly and simple but it gives us something to work with.

"We have noticed that every 10th time through our loop we get an error - we would like to stop execution and examine our object."

MyObject *myObject = [[MyObject alloc] init];

for (int i = 0; i < 1000; i++) {
  [myObject doSomething];        // Break point on this line
}

The old way

We set up a break point and we are happy to click continue as we only have to do it a few times. Hopefully our counting and hand to eye co-ordination is up to standard and we manage to click through correctly the first time to get us in the right state

click: Run 
click: Continue    
click: Continue  
click: Continue  
click: Continue  
click: Continue  
click: Continue  
click: Continue  
click: Continue  
click: Continue  
click: Continue  
Examine the object

We "fix" the issue but now it happens every 100th time through the loop. At this point we would probably abandon our tools and deteriorate to caveman debugging. Log everything and then scan the logs to see what is happening... but luckily we don't have to give up just yet.

Conditions

If you right click the breakpoint in Xcode you'll see an option to "Edit Breakpoint...".

Conditional Breakpoint Options

As you can see there are some interesting configuration options here.

  • Condition - A condition to be met for the breakpoint to fire
  • Ignore - Amount of times the condition needs to be met before firing
  • Action - Any actions to run which can be Applescript, Capture OpenGL frame, Debugger Command, Log Message, Shell Command, Sound
  • Options - As it says in the image

Remember using Debugger commands alone we can access all kinds of information like the values of variables, back traces etc

Basic condition

To start we'll set the condition and run an action to see if we can grab the 100th iteration

Conditional Breakpoint Options

Side note - p i will just print the variable i

We hit run and sure enough the debugger stops and in our console we get output like:

(int) $101 = 100
(lldb)

Basic condition with ignore

To try out the ignore option we'll stop on the 5th time that i == i, which will leave us with a value of 5.

Conditional Breakpoint Options

This gives us output like:

(int) $1 = 5
(lldb)

Non trivial condition

The Condition expression can be non trivial as long as llvm can understand it. For example if I wanted to examine the state around my object when one of the properties is set to the string broken I can get the breakpoint to fire like this:

Conditional Breakpoint Options

Apart from the annoying cast this is nice and clean.

"But I really like caveman debugging..."

You may be thinking "this is cool but I can just write the code that will print things when different conditions occur" - and you'd be right. There are two reasons why I prefer using the conditional breakpoint

  1. Where possible I don't like changing production code for development purposes.
  2. If I logged the object out I would only get the information that I logged. With the breakpoint I can examine all the state around the object as well because the execution is paused.

Crazy thoughts

I'm still only thinking about the wide range of debugging possibilities available but one far fetched scenario that could have uses in a collaborative environment could be for capturing those bugs that are hard to reproduce.

By setting up a conditional breakpoint and sharing it with the team, you could have multiple workstations + multiple developers going about their normal work but potentially capturing that awkward code path that you can never quite reproduce. At this point you can literally do anything - dump everything to a log, run a script to email you information, have the computer say "STOP you've found the lochness monster bug", who knows what fun you could have.

Conclusion

Conditional breakpoints are very flexible and powerful. Although I prefer to avoid the debugger by writing the best code I can, knowing how to use the tools effectively really helps out in times of need. Don't be fooled by only having 4 options to configure, these give you amazing power and versatility and should help avoid the times when you are stuck caveman debugging large repetitive tasks.