Being a developer means that many times a day you will end up debugging code, wether is yours or someone else’s. According to this research, we spend 25% of time fixing bugs and 25% making code works, at the end, we spend 50% of our time debugging. But sometimes I found myself spending whole day trying to catch a pesky bug or getting along a new project. More often you will have to debug spaghetti code.
Fortunately Xcode comes with amazing tools to make this task easier: LLDB & Instruments.
LLDB is the default debugger in Xcode (used to be GDB), comes with handy commands, also you can write your own debugging scripts using python and extend it’s functionality.
To help you understand this post I made a test project in github. I’m using Xcode Version 5.1.1 (5B1008).
Start Using LLDB.
Add a breakpoint to FGAppDelegate.
Run your app.
Navigate until you reach the breakpoint, you will see the LLDB console.
Print object values.
The command “po” evaluates C/ObjC/C++ expressions in the current program content, using defined variables and variables that are currently in scope. Which means that you will access solely the variables from the current class.
Add a breakpoint in FGViewController.m:40
Run the app.
When you hit the breakpoint type:
(lldb) po _person
You will get: nil (because is not yet initialised, press F6 to continue)
(lldb) po _person <FGPerson:0xc7762c0, ID:0 Name:John Doe>
po is useful to print objects, but if you need to print scalar values use (personID is an int property):
(lldb) p _person.personID (int) $2 = 0
Also you can use self:
(lldb)po self.view <UIView: 0xa08c030; frame = (0 0; 320 568); autoresize = RM+BM; layer = <CALayer: 0xa08c090>>
(lldb) po [[[UIApp delegate] window] recursiveDescription]
Remove previous breakpoint by right click at breakpoint->Delete
Add a breakpoint to a class and code line:
(lldb) b FGViewController.m:40
“Breakpoint 2:” = the id for the breakpoint, with this id you can add commands, delete, enable or modify a breakpoint.
Command Options (for more options type “help br” on LLDB prompt):
s: Sets a breakpoint or set of breakpoints in the executable. -n: Set the breakpoint by function name. -S: Set the breakpoint by ObjC selector name.
Add a breakpoint to a class and selector without parameters:
(lldb) br s -n "-[FGViewController setLabels]"
Add a breakpoint to a class and selector with parameters:
(lldb) br s -n "-[FGViewController addPersonHandler:]"
Add a breakpoint to a selector no matter the class:
(lldb) br s -S viewDidLoad
List all current breakpoints; added from LLDB or Xcode:
(lldb) br list
- Open the Breakpoint Navigator
- Click on + button
- Add Symbolic Breakpoint
- In Symbol text box write: -[FGViewController setLabels]
- Uncheck “Automatically continue after evaluating”.
Also you can read more about Xcode breakpoints in the post Xcode Breakpoint Wizardry from Big Nerd Ranch.
(lldb) b FGResizeViewController.m:53 Breakpoint 2: where = LLDBTest`-[FGResizeViewController resizeSquare:] + 198 at FGResizeViewController.m:53, address = 0x000029d6 (lldb) br mod -c "currentFrame.size.width > 200" 2
Adding a script to a breakpoint
For python scripts you have available these variables:
frame: a lldb.SBFrame object for the frame which hit breakpoint. bp_loc: a lldb.SBBreakpointLocation object that represents the breakpoint location that was hit. dict: the python session dictionary hit.
Adding a single line Python script that will print the current method for the breakpoint, this is really useful when you get into a new project and you want to trace where you’re passing while using the app:
(lldb) br s -S viewDidLoad Breakpoint 2: 18 locations. (lldb) br command add -s python 2 -o "function_name = frame.GetFunctionName(); print '%s' % function_name"
Adding a LLDB script:
(lldb) br command add -s command 2 Enter your debugger command(s). Type 'DONE' to end. > frame info > DONE frame #0: 0x0034bea5 UIKit`-[UIViewController viewDidLoad]
Debugging is one of the main developer’s activities, using the right tools provided by Xcode will help you easy this often tedious task. Now you know how to inspect data without adding NSLogs to your class files and most important, without stopping the app, which will save you a lot of time. Breakpoints are a powerful feature that you can use to stop conditionally or print more info about what is going on.
In LLDB type
for more info about all commands available.