What is LLDB?
LLDB is Xcode’s integrated low-level debugger, essential for examining and debugging applications across Apple’s platforms. It enables developers to set breakpoints, inspect variables, and navigate through code execution to diagnose and resolve issues efficiently. With support for both graphical and command-line interfaces, LLDB streamlines debugging workflows from simple variable checks to complex debugging tasks
How to Interact with LLDB?
LLDB allows different ways to interact with the application. such as po, p and v
Let’s take a look at below code Snippet.
enum ClassName {
case c1;
case c2;
case c3;
}
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func setName(name: String) {
self.name = name
}
}
class Student: Person {
var className: ClassName
init(name: String, age: Int, className: ClassName) {
self.className = className
super.init(name: name, age: age)
}
}
let student = Student(name: “vinay”, age: 26, className: .c1)
struct StudentStruct {
let name: String
let age: Int
}
let studentStruct = StudentStruct(name: “vinayStruct”, age: 26)
What is po?
In Xcode, po stands for “print object,” which is used to print the description of an object during debugging. When you use po followed by a variable name in the debugger console, it displays detailed information about that object.
For example, if you want to print the variable student, executing po student in the debugger console will display the object’s description or address.
For a variable like studentStruct, which is a struct type and already provides a default debugDescription method, po calls this method to show the detailed description of the object.
If you confirm the Student class to CustomDebugStringConvertible and override its debugDescription method as shown below:
var debugDescription: String {
return “Student((self.name), (self.age))”
}
var className: ClassName
init(name: String, age: Int, className: ClassName) {
self.className = className
super.init(name: name, age: age)
}
}
let student = Student(name: “vinay”, age: 26, className: .c1)
By implementing CustomDebugStringConvertible, you provide a custom implementation for the debugDescription property. When you use po student in the debugger console in Xcode, it automatically uses this custom debugDescription method to print a formatted description of the student object, incorporating its name, age, and any other relevant properties or state.
This demonstration clearly illustrates that po is utilized to display the object’s description while debugging.
That’s all po does? no, It can do more. you can even call the string methods on the name variable of the student
In general, It can evaluate any arbitrary expression.
In fact, po is alias for the command expression.
example:
you can even create your own po commands
my_po student
To unalias the created one use below command
What is p?
This is a second way of printing a variable in LLDB. You can think it as print without object description.
The representation differs slightly from the one provided by po. But it is equivalent as it gives the same information about the instance variables
p is an alias for the command expression but without –object-description flag
This p gives an incremental name to the result like $R0, $R1 etc.
if you use p in latest xcode version variables ex: $R0 name is not showing but it is showing if your using expression command. i am not sure why.
What is v?
To understand v, declare a variable studentWithBaseType as Person, not Student.
Since studentWithBaseType is of type Person, you cannot read properties specific to Student without casting it first, like accessing className on studentWithBaseType, which Swift’s compiler does not allow. To read it, you must cast it:
Similarly, LLDB dynamically resolves variable types only in expressions. Attempting to access properties directly on the result in LLDB results in an error, as shown below:
But By using v you can read the variables of the actual type Student in the LLDB console
Differences
po (print object):
Use: Print detailed object descriptions during debugging, especially useful for custom debug descriptions (CustomDebugStringConvertible).
When to Use: Use po when you need a formatted and detailed view of an object’s state, including custom debug descriptions.
p (print):
Use: Provides basic information about variables and objects without the detailed object description.
When to Use: Use p for quick checks on variable values or when detailed object description isn’t necessary, providing a concise view of the variable’s state.
v (dynamic resolution):
Use: Used for dynamically resolving types in LLDB expressions, essential when dealing with base types containing more specific class types.
When to Use: Use v to dynamically resolve and access properties specific to a subclass or more detailed class type within LLDB expressions.
Conclusion:
LLDB in Xcode offers powerful tools (po, p, v) for developers to debug applications comprehensively, from simple variable checks to complex debugging tasks, improving overall code quality and performance
for in-depth understanding refer this Apple World Wide Developer Conference – WWDC2019 Resouce