LLDB is a debugging tool that comes with Xcode. If you use this debugging tool well during the development process, it is not only an improvement of your ability, but also a magic tool to install force.
How to enter THE LLDB
When a program crashes or has a breakpoint, it automatically changes to LLDB mode. You can also do this manually by clicking here:
2. Use LLDB
2.1 expr instruction
This instruction is meant to execute code logic in real time. Something like this:
When you click Next, NSLog prints CoderHG instead of Coder. This feature feels pretty good when you think about it.
2.2 the call
This instruction, similar to expr, invokes a line of code that looks like this:
call self.view.backgroundColor = [UIColor redColor];
2.3 print
In fact, about printing, should all small partners know. Following the above steps, do the following:
There are two common print instructions p and Po in LLDB.
- 1. P is usually used to print values for basic data types. By default, this command produces a temporary variable, such as **$1**, which should be exciting to anyone who has studied the Shell.
- 2. Po prints the contents of a variable. In the case of an object, the printed contents are determined by -debugDescription.
2.4 Operating Memory
Operations on memory are nothing more than read and write operations. Modify the value in memory:
Memory Write Memory address value
Example: Memory write 0x7FFEE685dba8 25
Read memory operation:
Memory Read/Quantity _ Format _ Number of bytes Memory address
or
X/Quantity _ Format _ Number of bytes Memory address
Against 2.4.1 format
- X: indicates hexadecimal system
- F: floating point number
- D: indicates base 10
2.4.2 Byte size
- B: Byte indicates one byte
- H: Half word means 2 bytes
- W: Word stands for four bytes
- G: Giant word stands for eight bytes
Such as:
memory read/1wx 0x7ffee14a5ba8 memory read/1wd 0x7ffee14a5ba8
Read 4 bytes of 0x7FFEE14a5ba8. The following is an example:
2.5 bt
Bt returns all call stacks, as follows:
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
* frame # 0: 0x000000010758b6fd LLDBDev`-[ViewController viewDidLoad](self=0x00007fedad7057e0, _cmd="viewDidLoad") at ViewController.m:27I killed a lot of them in the middle. ** frame#34: 0x000000010758b79f LLDBDev`main(argc=1, argv=0x00007ffee8674108) at main.m:14
frame #35: 0x000000010c2d1d81 libdyld.dylib`start + 1
frame #36: 0x000000010c2d1d81 libdyld.dylib`start + 1
Copy the code
This directive is so powerful that the current Xcode doesn’t even show up here:
So we have to use BT instructions.
Third, in actual combat
No actual combat armchair strategist, are playing hooligan. To begin, define a Class as follows:
#import <Foundation/Foundation.h>
@interface HGObject : NSObject
/ * * * / age
@property (nonatomic.assign) NSInteger age;
/ * * * / tall
@property (nonatomic.assign) NSInteger height;
@end
#import "HGObject.h"
@implementation HGObject
@end
Copy the code
Very simple Class.
3.1 Viewing the ISA Pointer of an object
It is said that the value of isa in an instance is the value of the class of the current instance. Start with a simple piece of code:
Class cls = NSClassFromString(@"HGObject");
id obj = [[cls alloc] init];
NSLog(@ % @, % @ "", cls, obj);
Copy the code
Run code to find:
- 1. CLS does not display specific address values.
- 2. Isa is not seen in obj at all.
You can’t see any address display, so you can only use LLDB debugging tools, even using simple P or Po instructions is not possible. Use the instructions above to manipulate memory.
The value of isa for instance of a Class object is the value of the Class object itself. Yes, that’s the way it is.
3.2 Viewing an Address in an Object
Simple implementation of the following code:
HGObject* obj = [[HGObject alloc] init];
obj.age = 18;
obj.height = 2;
NSLog(@"% @", obj);
Copy the code
Make a breakpoint at NSLog, run the code, and open the memory view:
This is what it looks like when it first opens:
Write the address of obj and look at the following image:
Looking at the memory map above, I noticed a pattern, as shown below:
The memory distribution in the figure above, shown in the red box, is ISA, _age, and _height. To verify this, modify the values and see what happens:
The logic in the figure above looks like this: find the address of _age and _height, change the address value, and then refresh to see the memory view.
Memory breakpoints
As the name implies, to a memory break point. In fact, in the development, or very practical, a bit like KVO listening. Here is a simple test code with a manual breakpoint in viewDidLoad to enter the LLDB environment:
Once in the LLDB environment, we can execute the following commands:
watchpoint set variable self->_name
The log is:
Watchpoint created: Watchpoint 1: addr = 0x7fcfaf9061d0 size = 8 state = enabled type = w
watchpoint spec = 'self->_name'
new value: 0x0000000000000000
Copy the code
The breakpoint is successful. Select * from memory where id = ‘_name’;
Of course, the instruction to set memory breakpoints can also be like this:
watchpoint set expression &_name
Memory breakpoints are especially useful when analyzing data flows, such as when a variable is nil.
Five, UI control view
This function can be powerful, first look at a question:
This is actually a problem after we do automatic layout, the console will give you this prompt. If the interface is simple, it’s easy to troubleshoot. If the interface is complex, it’s hard to locate the problem. So how do you find the specific view? You can do it like this:
In this way, you can locate the UI on the interface in real time. The specific command is as follows:
(lldb) e id $hgView = (id)0x7fdfc66127f0
(lldb) e (void)[$hgView setBackgroundColor:[UIColor redColor]]
(lldb) e (void)[CATransaction flush]
Copy the code
Note: the command must be executed, otherwise it will not work in the LLDB state.
Dynamic injection of code logic
It is strange to see this subtitle, which means how to modify the logic of the code by modifying it while it is running. It’s a little convoluted, but let’s do a quick example.
6.1 a scene
There is the following code:
The yesOrNo attribute is used to set the value of yesOrNo to true when the code is already running and wants to run again. What would you do? In fact, the above introduction, using expR can be done, but there are more advanced can be. Create a breakpoint and double-click it to make it edit, as shown below.
Expression yesOrNo = true will save you from going to LLDB every time you run this breakpoint.
Such a break point, is not very high! ??
6.2 scenario 2
If you want to know when the value of an attribute changes, what should you do? Because a lot of times, a property change will happen in many places, so how to achieve uniform tracking? Here’s what I did many years ago: I overwrote the set method and then set a breakpoint in the set method. This is excellent, but also the most unsightly. Because after overwriting the set method, you need to delete it again, which is too damn tedious. Why not make a break point? Furthermore, what about tracking the change in system properties? Here’s a cool way to do it. Take the listener -[UILabel setText:] method as an example. The first step is to tease her:
Then dish her up like this:
-[UILabel setText:]
Then, to your surprise, nothing is done and the breakpoint is triggered:
rogue
I only want to listen for -[UILabel setText:] triggered in btn1. What should I do? In real development, the BTN1 approach might be complex. Directly give the final treatment scheme:
This is a familiar picture. Breakpoint set-one-shot true –name “-[UILabel setText:]” breakpoint set-one-shot true –name “-[UILabel setText:]” Will be automatically triggered to trace.
What exactly does this break point do? You can just imagine it.
Seven, section
A common fix cycle is to modify the code, compile it, re-run it, and hope for the best.
Familiarizing yourself with some common LLDB debugging techniques can save you a lot of debugging time in actual development.
Viii. Other excellent articles
2. Xcode debug LLDB