Debugging techniques in Xcode are closely related to our daily development, and these debugging techniques can be used to solve bugs, often with various breakpoints and commands. These debugging tips are often asked in interviews, so check them out if you don’t know.
Debugging commands
In the figure above, the green area on the right is the Log output area, where commands can be used to aid debugging.
What are the debugging commands?
To see all the debugging commands, type help in the right field of the image above to list all the debugging commands. This article introduces a few use frequency relatively high, others check, understand it by yourself.
1. The p command
- ('expression --') Evaluate an expression on the current thread.
Displays any returned value with LLDB's default formatting.
Copy the code
The p command is short for the print command. You can view the values of the basic data types using the p command, but if you view objects using the p command, only the pointer address of the object will be returned.
The p command can be followed by variables, constants, and expressions. (❌ but macros ❌ cannot be used)
2. Po orders
The Po command can be understood as printing objects. The function is similar to the p command, so it can also print constants, variables, and objects returned by expressions. (❌ also cannot print macros ❌)
Print Description of “XXX” : print Description of “XXX”
Of course, there are other ways to print:
3. The expr command
Expr is short for expression. Using the expr command, you can dynamically execute the assignment expression and print the result during debugging. We can change the value of a variable dynamically during debugging, which is useful when debugging an application that wants to execute an exception path (such as an else case).
(lldb) p i
(NSInteger) $16 = 1
(lldb) expression i = 5
(NSInteger) $17 = 5
(lldb) po i
5
Copy the code
4. Call command
The above is to change the value of a variable dynamically, Xcode also supports dynamic calling of functions. By running this command on the console, you can modify the view on the interface without modifying the code or recompiling it. Here is an example of dynamically removing a subview of a cell:
(lldb) po cell.contentView.subviews
<__NSArrayM 0x60800005f5f0>(
<UILabel: 0x7f91f4f18c90; frame = (5 5; 300 25); text = '2 - Drawing index is top ... '; userInteractionEnabled = NO; tag = 1; layer = <_UILabelLayer: 0x60800009ff40>>, <UIImageView: 0x7f91f4d20050; frame = (105 20; 85, 85); opaque = NO; userInteractionEnabled = NO; tag = 2; layer = <CALayer: 0x60000003ff60>>, <UIImageView: 0x7f91f4f18f10; frame = (200 20; 85, 85); opaque = NO; userInteractionEnabled = NO; tag = 3; layer = <CALayer: 0x608000039860>> ) (lldb) call [label removeFromSuperview] (lldb) po cell.contentView.subviews <__NSArrayM 0x600000246de0>( <UIImageView: 0x7f91f4d20050; frame = (105 20; 85, 85); opaque = NO; userInteractionEnabled = NO; tag = 2; layer = <CALayer: 0x60000003ff60>>, <UIImageView: 0x7f91f4f18f10; frame = (200 20; 85, 85); opaque = NO; userInteractionEnabled = NO; tag = 3; layer = <CALayer: 0x608000039860>> )Copy the code
5. The bt command
The BT command prints the stack information for the thread, which is more detailed than the Debug Navigator on the left sees.
The bt command prints the stack information for the current thread
(lldb) bt
* thread # 1: tid = 0x27363, 0x000000010d204125 TestDemo`-[FifthViewController tableView:cellForRowAtIndexPath:](self=0x00007f91f4e153c0, _cmd="tableView:cellForRowAtIndexPath:", tableView=0x00007f91f5889600, indexPath=0xc000000000400016) + 2757 at FifthViewController.m:91, queue = 'com.apple.main-thread', Stop Reason = breakpoint 6.1
* frame # 0: 0x000000010d204125 TestDemo`-[FifthViewController tableView:cellForRowAtIndexPath:](self=0x00007f91f4e153c0, _cmd="tableView:cellForRowAtIndexPath:", tableView=0x00007f91f5889600, indexPath=0xc000000000400016) + 2757 at FifthViewController.m:91
frame #1: 0x0000000111d0a7b5 UIKit`-[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 757
frame #2: 0x0000000111d0aa13 UIKit`-[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 74
frame #3: 0x0000000111cde47d UIKit`-[UITableView _updateVisibleCellsNow:isRecursive:] + 3295
frame #4: 0x0000000111d13d95 UIKit`-[UITableView _performWithCachedTraitCollection:] + 110
frame #5: 0x0000000111cfa5ef UIKit`-[UITableView layoutSubviews] + 222
frame #6: 0x0000000111c61f50 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1237
frame #7: 0x00000001117a5cc4 QuartzCore`-[CALayer layoutSublayers] + 146
frame #8: 0x0000000111799788 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 366
frame #9: 0x0000000111799606 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 24
frame #10: 0x0000000111727680 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 280
frame #11: 0x0000000111754767 QuartzCore`CA::Transaction::commit() + 475
frame #12: 0x00000001117550d7 QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 113
frame #13: 0x0000000110743e17 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
frame #14: 0x0000000110743d87 CoreFoundation`__CFRunLoopDoObservers + 391
frame #15: 0x0000000110728b9e CoreFoundation`__CFRunLoopRun + 1198
frame #16: 0x0000000110728494 CoreFoundation`CFRunLoopRunSpecific + 420
frame #17: 0x0000000114390a6f GraphicsServices`GSEventRunModal + 161
frame #18: 0x0000000111b9d964 UIKit`UIApplicationMain + 159
frame #19: 0x000000010d21294f TestDemo`main(argc=1, argv=0x00007fff529fe620) + 111 at main.m:14
frame #20: 0x000000011458a68d libdyld.dylib`start + 1
(lldb)
Copy the code
The bt all command prints stack information for all threads. Too much information is printed out, so I won’t show it!
6. Image command
The image list command lists all modules in the current App (this module will be used later for symbol breakpoints), and you can see the code location of an address. In addition to image list, there are image add, image lookup and other commands, you can view them by yourself. When crash occurs, only the address of stack frame can be seen by checking the thread stack. The image lookup-address address can be used to conveniently locate the code line corresponding to this address.
The breakpoint
Breakpoints in Xcode are also very learned, there are ordinary breakpoints, conditional breakpoints, symbolic breakpoints, exception breakpoints, and many other types.
1. Normal breakpoint
To make a normal breakpoint, just find the corresponding line and click on the left side of the code.
2. Conditional breakpoints
Conditional breakpoints are useful breakpoints, especially in for loops. Conditional breakpoints can be used if we need to add a breakpoint at I = 5 and not at other times. A conditional Breakpoint is a normal Breakpoint where you right-click and select Edit Breakpoint… , and then set a condition
3. Symbolic breakpoints
A Symbolic Breakpoint is a Symbolic Breakpoint, which is a Breakpoint for a specific function, either an OC function or a C++ function. The additions are as follows:
image
Symbol breakpoints are useful in debugging some modules without source code, such as debugging a third-party Lib library, or system modules. Breakpoints can be set at the corresponding function, and the running process of the program can be roughly debugged. Parameter information can also be viewed at the time of breakpoints.
4. Abnormal breakpoints
If the program crashes, we can make an exception breakpoint, so that the breakpoint will be triggered when it crashes. It is easy to locate the problem, and we can see more information about the crash, such as Log, function call stack.
Note: Some programs or functions may use exceptions to organize program logic, such as calling AVAudioPlayer, which causes breakpoints to be triggered when running into AVAudioPlayer. We can fix this by modifying the Exception parameter or removing the Exception breakpoint.
5. Watch the breakpoint
Triggered when a variable changes. Create a Watch breakpoint:
So much for the breakpoints and commands in Xcode debugging tips, and more useful ones in the future.