Search code examples
swiftxcodelldb

Add line break to Xcode output


Say you have a custom object which has a custom description like so:

class CustomObject {

    var customDescription: String {
        return "Title: Hello, \n Subtitle: World"
    }
}

Is there a way to have the line break \n work in the console when printing it using the po command in the LLDB console?

Right now LLDB prints the \n as part of the text and doesn't process it:

po object.customDescription
> "Title: Hello, \n Subtitle: World"

Where the desired result is:

po object.customDescription
> Title: Hello
  Subtitle: World

Do you have any solution for this?


Solution

  • I don't want to discourage you from making an lldb data formatter for your classes. They have the advantage over po that they give lldb a way to show you a summary representation of your data without having to call code in the running program. Also, if you use Xcode, the Xcode locals view will show your data formatters automatically.

    But to clear up the way po works:

    The lldb po command works by calling the language-specified description method for the object that the expression you provide resolves to. So for instance in your example, you were seeing the result of the description method for the Swift String class, which displays the "programmer's view" of the string.

    In the case of Swift, there are a couple of ways to provide a description. The simplest is to implement the CustomStringConvertible protocol:

    class CustomObject : CustomStringConvertible {
    
        var description: String {
            return "Title: Hello,\n Subtitle: World"
        }
    }
    
    func main()
    {
      let my_object = CustomObject()
      print (my_object)
    }
    
    main()
    

    Then when you debug this, you see:

    (lldb) br s -p print
    Breakpoint 1: where = desc`desc.main() -> () + 27 at desc.swift:11, address = 0x000000010000116b
    (lldb) run
    Process 69112 launched: '/private/tmp/desc' (x86_64)
    Process 69112 stopped
    * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
        frame #0: 0x000000010000116b desc`desc.main() -> () at desc.swift:11
       8    func main()
       9    {
       10     let my_object = CustomObject()
    -> 11     print (my_object)
                     ^
       12   }
       13   
       14   main()
    Target 0: (desc) stopped.
    (lldb) po my_object
    Title: Hello,
     Subtitle: World
    
    (lldb) c
    Process 69112 resuming
    Title: Hello,
     Subtitle: World
    Process 69112 exited with status = 0 (0x00000000) 
    

    Note here that both po and the swift print function render your object the same way.

    If you want separate debug and print descriptions, then you also implement CustomDebugStringConvertible which requires a debugDescription property. Then po will print the debugDescription but print will print the description.

    If you want to get fancier, or want to have po represent the "structure" of your object the way the po result for Swift Arrays (for example) does, you can make a custom Mirror for your class. There's documentation on that here:

    https://developer.apple.com/documentation/swift/mirror

    and if that isn't clear, the implementation of Mirrors is in the swift sources in:

    https://github.com/apple/swift/blob/master/stdlib/public/core/Mirror.swift