LLDB comes with a great set of commands for powerful debugging.
Your starting point for anything. Type help
to get a list of all commands, plus any user installed ones. Type 'help <command-name>
for more information on a command. Type help <command-name> <option>
to get help for a specific option in a command too.
This is how you search in lldb for a command, or an option. apropos <search-term>
should help you find what you're looking for.
Setting breakpoints in lldb is easy.
breakpoint set -l <line-number>
; sets a breakpoint on a line in the current context.breakpoint set --file <file-name> -l <line-number>
; sets a breakpoint on a line on a given file.breakpoint set --name <method-name>
; sets a breakpoint on a given function name, globally. e.g.,breakpoint set --name viewDidLoad
orbreakpoint set --name "-[UIView setFrame:]"
.breakpoint set --selector <selector-name>
; sets a breakpoint on a selector, globally. e.g.,breakpoint set --selector dealloc
.
Expression can help you evaluate code! Helpful when you need to change some stuff, but can't recompile for some reason.
expr <return-type><expression>
; e.g.,expr (UIViewController *)[((UIViewController *)0x7f9492b70570).navigationController popViewControllerAnimated:YES]
By default, running an expression ignores breakpoints. You can force it to stop on any relevant breakpoints with --ignore-breakpoints
.
expr --ignore-breakpoints false -- <expression>
; e.g.,expression --ignore-breakpoints false -- [self methodName]
You can even create new code and evaluate it inline.
expr for (int i = 0; i < 5; i++) { (void)NSLog(@"Meow"); }
Setting a global variable can help you keep around a reference to a given object, as long as it isn't deallocated from memory.
expr <type-name> $<variable-name> = <r-value>
; e.g.,expr UIWindow* $variable_name = 0x10d72852e
.
Then you can use that variable to your hearts content. Omitting $
sets the scope for the variable only locally defined.
expr <type-name> <variable-name> = <r-value>
; e.g.,expr UIWindow* variable_name = 0x10d85832e
.
Manipulating the program counter with thread
is super awesome.
If you spend all your time clicking step and step and step in xcode to get to a specific line, thread until
can help you do this faster. thread until
will continue all execution until that line, even if it is well inside several lines of conditional code.
thread until <line-number>
; e.g.,thread until 45
Even better, what if you want to skip the execution of a few lines? You could of course comment the lines out and recompile, but thread jump
is faster.
thread jump -b <offset>
; e.g.,thread jump -b 2
will jump to two lines away, skipping those two lines in between.
Combine this with a breakpoint that continues after evaluation and suddenly you've permanently commented out two lines without even recompiling.
What if you want to just stop executing anything in a method you're in?
thread return
Need to know where you are in the stack?
thread backtrace
Need to know when a variable pointer changes? Use watchpoint set
.
watchpoint set <variable-name>
; e.g.,watchpoint set _imageView
.
Variable exists inside another object?
watchpoint set variable <object-name>-><variable-name>
' e.g.,watchpoint set variable self->personImageView
.
Print out a list of all variables in the current frame. Very useful when you don't like the way Xcode shows variables.
frame variable
Need to know where you are?
frame info
https://github.com/facebook/chisel
Chisel adds a number of awesome lldb commands that can help you debug like a master. Install it using the instructions provided and you can use the commands in LLDB just like the standard ones. If they sometimes done work, run command source ~/.lldbinit
to load them again instead of closing and reopening Xcode.
Prints out a list of all view controllers currently displayed. Helpful when you need to start digging after pausing execution and you don't have the context you'd get from a breakpoint. Works by finding all displayed UIWindow instances, and starting from rootViewController
.
pvc
Prints out a recursive description of all views and subviews.
pviews
Helps you find a specific view currently on screen.
fv <search-term>
; e.g.,fv imageView
.
Helps you find a specific view controller currently displayed.
fvc <search-term>
; e.g.,fvc requestviewcontroller
.
Debug the responder chain for a control.
presponder <variable-name>
; e.g.,presponder _nameTextField
.
Same thing as breakpoint set --selector
. A little smarter in that it goes up the superclass hierarchy if it doesn't find the selector, and sets the breakpoint when it does even if it's in a superclass.
bmessage <expression>
; e.g.,bmessage "-[MyView setFrame:]"
.
Given a view, visualize
will composite all the subviews of the view into one image, save it to a PNG, and open it in Preview.app.
visualize <view-variable-name>
; e.g.,visualize _tableView
.
Shows and hides a view or layer.
-
show <view-variable-name>
; e.g.,show _tableView
. -
hide <view-variable-name>
; e.g.,hide _tableView
.
Prints a JSON representation of an NSArray or NSDictionary.
pjson <object-variable-name>
; e.g.,pjson dictionary
.
Prints a string representation of an NSData object.
pdata <object-variable-name>
; e.g.,pdata data
.
The default encoding is UTF-8, which is analogous to typing this in LLDB (where 4
== NSUTF8StringEncoding
):
po (NSString *)[[NSString alloc] initWithData:data encoding:(NSStringEncoding)4]
Amazing command if you work heavily with networking code. Converts an NSURLRequest to a curl command and spits it out.
pcurl <object-variable-name>
; e.g.,pcurl urlRequest
.
Simulates a memory warning.
mwarning
Analogous to typing this in LLDB:
expr (void)[[UIApplication sharedApplication] performSelector:@selector(_performMemoryWarning)]
Similar to the View Debugger in Xcode 6, but actually useful. You can change fields, toggle properties, and see classes Apple doesn't want you to see.