13

When I use print() on a dictionary in Swift, it comes out nice and pretty in the console, with a key and a value.

object = Optional({
customerId = 111;
transactionId = 333;
extraId = 444;
})

When I run po on that same dictionary, it spits out this nonsense dump which is incredibly hard to read.

▿ Optional<Any>
▿ some : 3 elements
▿ 0 : 2 elements
  ▿ .0 : transactionId
  - .1 : 333
▿ 1 : 2 elements
  ▿ .0 : customerId
  - .1 : 111
▿ 2 : 2 elements
  ▿ .0 : extraId
  - .1 : 444

Using just p is even worse

(Any?) $R8 = some {
  payload_data_0 = 0x0000000170e679c0 {
  Swift._SwiftNativeNSDictionary = {}
  _heapBufferBridged_DoNotUse = 0x0000000170e679d0 {}
  nativeStorage = {
    buffer = 0x00000001703e4300 {
      Swift.ManagedBuffer = {}
    }
    initializedEntries = (values = 0x00000001703e4328, bitCount = 4)
    keys = 0x00000001703e4330
    values = 0x00000001703e4390
    }
  }
  payload_data_1 = 0x0000000000000000
  payload_data_2 = 0x0000000000000000
  instance_type = 0x0000000105ffc3f8
}

What can I do in the console to see my variables in a way that I can actually read them without having to sift through all this nonsense?

PS - In this case I am printing an Optional<Any> object that happens to be a dictionary, but it's the same with a non-optional Dictionary.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
teradyl
  • 2,584
  • 1
  • 25
  • 34
  • What does `p object!` print in the debugger? – Martin R Feb 14 '17 at 21:56
  • 1
    You should look into LLDB Data Formatters. I don't have the chops to make it work but here's [Advanced Swift Debugging in LLDB](https://developer.apple.com/videos/play/wwdc2014/410/) from WWDC 2014. Data Formatter is presented around the 34-minute mark. – Code Different Feb 15 '17 at 02:46
  • Duplicate of [this topic](https://stackoverflow.com/questions/38773979/is-there-a-way-to-pretty-print-swift-dictionaries-to-the-console/) though I provided a new solution [below](https://stackoverflow.com/questions/42236555/prettier-debug-output-printing-swift-dictionary-in-xcode#63910097) – agirault Sep 15 '20 at 21:56

2 Answers2

25

New answer (2021):

The fastest way to get readable output is to use:

po print(data)

Say, you have variable data like below:

let data: [String: Any] = ["value1": 64, "value2": true, "value3": "some"]

When you do po print(data), you will get following output:

(lldb) po print(data)
["value1": 64, "value2": true, "value3": "some"]
0 elements

If you're not in a rush you can improve debug printing format following steps from answer in below.

OLD answer (2017):

expression debugPrint(object)

just put the line above in your debugger and hit enter. It will print out contents of our object in more human readable format.

also you can use another one command - po print(data), which is easier to remember.

Stanislau Baranouski
  • 1,425
  • 1
  • 18
  • 22
18

⚠️ The (previously) accepted answer only provided the dictionary as a non-formatted single line string like so:

Optional(["transactionId": 333, "customerId": 111, "extraId": 444])

➡️ As soon as you get more keys and embedded objects/dictionaries it becomes difficult to read.


PrettyPrint JSON solution

  • To get a nice json formatting (indentations, newlines, etc) you can define an alias (I named mine pjson) by running this command in your lldb terminal (source):
command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'
  • You probably don't want to re-define the alias everytime you open Xcode, so run the following command to append the alias definition to ~/.lldbinit:
echo "command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'" >> ~/.lldbinit
  • This will create the pjson alias which you can use in your lldb terminal in Xcode:
pjson object

Comparing the outputs for the following Swift object:

let object: Any? = [
    "customerId": 111,
    "transactionId": 333,
    "extraId": 444,
    "embeddedDict": [
        "foo": true
    ]
]

❌ Output of po print(data)

Optional(["transactionId": 333, "embeddedDict": ["foo": true], "customerId": 111, "extraId": 444])

✅ Output of pjson

{
  "transactionId" : 333,
  "embeddedDict" : {
    "foo" : true
  },
  "customerId" : 111,
  "extraId" : 444
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
agirault
  • 2,509
  • 20
  • 24
  • entering your permanent `echo` command in Terminal results in `zsh: event not found: ))/` and/or ``bash: !: event not found``. Do you know the problem or how to fix? – pkamb Apr 22 '21 at 16:40
  • 2
    @pkamb Looks like you're running into this: https://serverfault.com/questions/208265/what-is-bash-event-not-found#comment806622_208266 Probably can be worked around by escaping some characters, but I'm not going to play that game. Instead, you can just copy the command (between the double quotes, or listed above), and add it to the `~/.lldbinit` file. – agirault Apr 27 '21 at 15:52
  • How can I get a value selected from the dictionary content? – SimonKravis Mar 28 '22 at 01:04