PO vs P vs V in LLDB of Xcode

PO vs P vs V in LLDB of Xcode

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.

import Foundation

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.

po student

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.

po studentStruct

If you confirm the Student class to CustomDebugStringConvertible and override its debugDescription method as shown below:

class Student: Person, CustomDebugStringConvertible {
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

po student.name.uppercased()

In general, It can evaluate any arbitrary expression.

In fact, po is alias for the command expression.

example:

expression –object-description — student

you can even create your own po commands

command alias my_po expression –object-description —
my_po student

To unalias the created one use below command

command unalias my_po

What is p?

This is a second way of printing a variable in LLDB. You can think it as print without object description.

p student

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.

let studentWithBaseType: Person = Student(name: “vinaywithbasetype”, age: 26, className: .c1)

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:

(studentWithBaseType as! Student).className

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

v studentWithBaseType.className

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

Please follow and like us:
Pin Share