Intermediate Debugging with Xcode 4.5

This is a tutorial for intermediate iOS developers, where you’ll get hands-on experience with some extremely useful debugging techniques. By Brian Moakley.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Breakpoints and Expressions

So far so good, but you may have noticed that the breakpoint logging doesn’t show a timestamp of when the log message occurs, which can sometimes be useful for debugging purposes. The good news is it’s easy to fix with breakpoint expressions!

Note: Date logging is indeed useful, but keep in mind it also makes the logging a bit slower as it has to query all the date information. Keep that in mind if you find your logging calls lagging behind your application.

Let’s restore your log statements to their previous glory. Right click or control click the previous breakpoint in FriendSelectionViewController.m. Click ‘Edit Breakpoint’. In the debugger action, change the command to read:

expr (void)NSLog(@"dataStore: %@", dataStore)
expr (void)NSLog(@"dataStore: %@", dataStore)

The expr command will evaluate an expression in real time. The expression command needs to know the actual type of the returning value, so a cast is necessary. Since there is no return type for NSLog, the return type is cast to a void value. Build and run.

You should now see the following:

<b>2012-12-20 08:57:39.942 GiftLister[1984:11603] dataStore: <DataStore: 0x74c3170></b>
<b>2012-12-20 08:57:39.942 GiftLister[1984:11603] dataStore: <DataStore: 0x74c3170></b>

Being able to add NSLog messages via. breakpoints means you no longer have to stop the program just to log important data, there’s no chance of introducing new bugs because you are not touching the code, but best of all, there’s no last minute scrambles to remove all your debug statements the night before release.

There is one small difference between calling NSLog in the debugger versus calling it in the code. Underneath the actual log message, the text “<no result>” is printed. This is generated from LLDB and unfortunately, you cannot suppress this message. The good news is that this message should be going away in Xcode’s next point release.

Now let’s disable logging in the app. It’s just a matter of pressing the breakpoints button.

Click it and then build and run. Your logs are clean.

You can also individually turn off log calls by heading over to the breakpoint navigator.

The days of filling your codebase with commented out log calls are now over! :]

Warnings, Errors, Return Values, oh my!

The app is running. The next thing to do is to create some friends so you can keep a list of gift suggestions for them.

Build and run the app, and when the app starts, press the table cell which says, “Add a friend”. The app loads another view controller with a name text field and a date picker. Enter a name and select a birthday. Press the OK button.

You’ll be returned back to the root controller with your new friend added to the table. Click the “Add a friend” cell once again.

Enter the name of another friend, only this time, for the birthday, select February 31st, 2010.

In a typical date picker such a date would not be pickable. This is not the case with this app. In a fit of delirium, I decided to be ambitious by choosing the regular picker instead of the date picker. Doing so, I was forced to rewrite all of the date validation logic which, of course, created some new bugs.

Press the OK button. Tragically, the invalid date is recorded. It’s time to do a little debugging to see what is wrong.

Open the AddFriendViewController.m and add a breakpoint at the start of the method -(void)saveFriend.

Note: Finding methods in large files can take a lot of time. The long way is to manually scan each line until you stumble into it. The second way is to use the jump bar, then scroll through the list of method names. I actually prefer to do a search, although not in the search navigator, but in the jump bar itself. To do so, click on the jump bar then just start typing. Your method name should show up like it were in a regular search field.

In the simulator, press the “Add a friend” button and like your previous entry, add an invalid date. Step down the method until you reach this line:

if ([self isValidDateComposedOfMonth:month day:day andYear:year]) {
if ([self isValidDateComposedOfMonth:month day:day andYear:year]) {

Step into method. The validation code failure is clear. There isn’t any. There’s just a comment promising to do it sometime in the future.

Comments are nice way to describe the particular meaning of code chunks, but using them for task management is futile. Even on tiny projects, there’s just too many items to juggle that these comment tasks will be forgotten.

The best way to prevent them from being lost is to really make them stand out.

In the first line of the method -(void)isValidDateComposedOfMonth, write the following line of code:

#warning add validation code
#warning add validation code

Right away, the project will report a new warning. Click on the Issue Navigator and you’ll see the warning listed, along with your message.

If you are the type of developer who ignores warnings, try out this variation of it:

#error fix your code
#error fix your code

Right away, the new error is reported. You will be unable to compile your code until that line is deleted. That’s one way to keep track of your comments :]

Delete both the messages so the app will compile.

You can also leave messages in the jump bar. In the first line of the method -(void)isValidDateComposedOfMonth, write the following line of code:

// TODO: Add validation code
// TODO: Add validation code

Save the file, then open the jump bar. You should see something like this:

You can also write: FIXME:, ???:, and !!!:. The ???: means, “I have a question for you” whereas the !!!: means, “this is important”.

These statements don’t have the same emphasis as the compiler warning or error, but they at least have a greater visibility than a lone comment at the bottom of a method. It’s best to leave comments for, well, comments and keep a list of required tasks outside of the codebase.

Now let’s investigate a nice little feature that was included in Xcode 4.4.

Restart the app, keeping the breakpoint fixed in the empty validation method. Now, step out of the code. Look at the Variables view in the debugger. You should see this:

This is a feature that hasn’t received much attention, but it makes your life so much easier. Consider that the code was being called from here:

if ([self isValidDateComposedOfMonth:month day:day andYear:year]) {
if ([self isValidDateComposedOfMonth:month day:day andYear:year]) {

The code that is calling the method then immediately using the return value in an expression. Prior to this being added in Xcode, if you wanted to inspect return values, you needed to break apart the line, then log out the value.

Now, you can just step out of a method and see the return value right in the debugger.

Contributors

Over 300 content creators. Join our team.