Is there a way to pretty print Swift dictionaries to the console?

NSDictionary *dictionary = @{@"A" : @"alfa",
@"B" : @"bravo",
@"C" : @"charlie",
@"D" : @"delta",
@"E" : @"echo",
@"F" : @"foxtrot"};
NSLog(@"%@", dictionary.description);

prints out the following on the console:

{
A = alfa;
B = bravo;
C = charlie;
D = delta;
E = echo;
F = foxtrot;
}

let dictionary: [String : String] = ["A" : "alfa",
"B" : "bravo",
"C" : "charlie",
"D" : "delta",
"E" : "echo",
"F" : "foxtrot"];
print(dictionary)

prints out the following on the console:

["B": "bravo", "A": "alfa", "F": "foxtrot", "C": "charlie", "D": "delta", "E": "echo"]

Is there a way in Swift to get it to pretty print dictionaries where each key-value pair occupies a new line?

92490 次浏览

您可以只使用 for 循环并打印每个迭代

for (key,value) in dictionary {
print("\(key) = \(value)")
}

延期申请:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {


var prettyprint : String {
for (key,value) in self {
print("\(key) = \(value)")
}


return self.description
}
}

备选用途:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {


func prettyPrint(){
for (key,value) in self {
print("\(key) = \(value)")
}
}
}

用法:

dictionary.prettyprint //var prettyprint
dictionary.prettyPrint //func prettyPrint

输出(在 Xcode 8 beta 2 Playground 中测试) :

A = alfa
B = bravo
C = charlie
D = delta
E = echo
F = foxtrot

这个怎么样:

import Foundation


extension Dictionary {
var myDesc: String {
get {
var v = ""
for (key, value) in self {
v += ("\(key) = \(value)\n")
}
return v
}
}
}




// Then, later, for any dictionary:
print(dictionary.myDesc)

只是使用函数式编程的另一种方法

dictionary.forEach { print("\($0): \($1)") }

Output

B: bravo
A: alfa
F: foxtrot
C: charlie
D: delta
E: echo

You could use dump, for example, if the goal is to inspect the dictionary. dump is part of Swift's standard library.

用法:

let dictionary: [String : String] = ["A" : "alfa",
"B" : "bravo",
"C" : "charlie",
"D" : "delta",
"E" : "echo",
"F" : "foxtrot"]


dump(dictionary)

产出:

enter image description here


dump通过反射(镜像)打印对象的内容。

数组的详细视图:

let names = ["Joe", "Jane", "Jim", "Joyce"]
dump(names)

印刷品:

Something 4种元素


吉姆
乔伊斯

对于字典:

let attributes = ["foo": 10, "bar": 33, "baz": 42]
dump(attributes)

印刷品:

▿ 3 key/value pairs
Something [0] : (2个元素)
- 。0: 酒吧
- 1:33
▿ [1]: (2 elements)
- 。0: 巴兹
- 1:42
▿ [2]: (2 elements)
- 。0: foo
- 1:10

dump被声明为 dump(_:name:indent:maxDepth:maxItems:)

第一个参数没有标签。

还有其他可用的参数,比如 name,用于为被检查的对象设置标签:

dump(attributes, name: "mirroring")

印刷品:

Something miroring: 3个键/值对
Something [0] : (2个元素)
- 。0: 酒吧
- 1:33
Something [1] : (2个元素)
- 。0: 巴兹
- 1:42
Something [2] : (2个元素)
- 。0: foo
- 1:10

您还可以选择使用 maxItems:只打印一定数量的项目,使用 maxDepth:解析到一定深度的对象,并使用 indent:更改打印对象的缩进。

仅为了调试的目的,我将 Array 或 Dictionary 转换为一个漂亮的打印 json:

public extension Collection {
    

/// Returns: the pretty printed JSON string or an error string if any error occur.
var json: String {
do {
let jsonData = try JSONSerialization.data(withJSONObject: self, options: [.prettyPrinted])
return String(data: jsonData, encoding: .utf8) ?? ""
} catch {
return "json serialization error: \(error)"
}
}
}

然后:

print("\nHTTP request: \(URL)\nParams: \(params.json)\n")

控制台上的结果:

HTTP request: https://example.com/get-data
Params: {
"lon" : 10.8663676,
"radius" : 111131.8046875,
"lat" : 23.8063882,
"index_start" : 0,
"uid" : 1
}

对我来说,最简单的解决方案就是将字典设置为“ AnyObject”:

let dictionary = ["a":"b",
"c":"d",
"e":"f"]
print("This is the console output: \(dictionary as AnyObject)")

this is the console output

对我来说,这比 dump 选项更容易阅读,但是请注意,它不会给出键值的总数。

extension String {


var conslePrintString: String {


guard let data = "\""
.appending(
replacingOccurrences(of: "\\u", with: "\\U")
.replacingOccurrences(of: "\"", with: "\\\"")
)
.appending("\"")
.data(using: .utf8) else {


return self
}


guard let propertyList = try? PropertyListSerialization.propertyList(from: data,
options: [],
format: nil) else {
return self
}


guard let string = propertyList as? String else {
return self
}


return string.replacingOccurrences(of: "\\r\\n", with: "\n")
}
}


let code in extension String and it works fine


let string = "\(jsonDictionary)".conslePrintString

po溶液

对于那些希望在 控制台中将 Dictionary 看作没有转义序列的 JSON 的人,这里有一个简单的方法:

(lldb) p print(String(data: try! JSONSerialization.data(withJSONObject: object, options: .prettyPrinted), encoding: .utf8)!)

更新

Check out 这个答案 too.

对于 Swift 3(和建立在 @ Jalakoo精彩答案的基础上) ,使用以下 Dictionary扩展:

extension Dictionary where Key: ExpressibleByStringLiteral, Value: Any {
var prettyPrint: String {
return String(describing: self as AnyObject)
}
}

然后使用以下方法以 pretty的方式(优于 dump())打印 任何等级制度的字典:

print(dictionary!.prettyPrint)

将 Swift Dictionary 转换为 json 和 back 的方法是最简洁的。我使用 Facebook 的 chisel,它有一个 pjson命令来打印 Swift 字典。 例如:

(lldb) pjson dict as NSDictionary

这应该可以很好地打印字典。这是一个更干净的方法来做已经建议的事情。 附言。 现在,您必须将 dict 转换为 NSDictionary,因为 Objective-C 运行时不理解 Swift 字典。为了摆脱这种限制,我已经对凿子进行了公关。

UPDATE: My PR got accepted. Now you can use Psjson command instead of Pjson mentioned above.

我不会认为这里提供的很多答案都是真正的打印好的 JSON,因为当您将结果传递到 JSON 验证器时,结果是无效的(通常是由于代码包括’=’而不是’:’)。

The easiest way I've found of doing this is just converting the JSON object to data using the pretty printed writing option then printing a string using the resulting data.

Here is an example:

let jsonData = try! JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)


if let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
}

Result:

{
"jsonData": [
"Some String"
],
"moreJSONData": "Another String",
"evenMoreJSONData": {
"A final String": "awd"
}
}

编辑 : 有人指出,OP 并没有要求使用 JSON,但是我发现,建议只打印或转储数据到控制台的答案提供了很少的格式(如果有的话) ,因此打印效果并不好。

我相信,尽管 OP 没有要求使用 JSON,但是它是一个可行的答案,因为它是一种更易读的数据格式,而不是由 xcode/swift 向控制台输出的可怕格式。

细节

  • Xcode 10.2.1(10E1001) ,Swift 5

解决方案

extension Dictionary {
func format(options: JSONSerialization.WritingOptions) -> Any? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: self, options: options)
return try JSONSerialization.jsonObject(with: jsonData, options: [.allowFragments])
} catch {
print(error.localizedDescription)
return nil
}
}
}

用法

let dictionary: [String : Any] = [
"id": 0,
"bool": true,
"int_array": [1,3,5],
"dict_array": [
["id": 1, "text": "text1"],
["id": 1, "text": "text2"]
]
]
print("Regualr print:\n\(dictionary)\n")
guard let formatedDictionary = dictionary.format(options: [.prettyPrinted, .sortedKeys]) else { return }
print("Pretty printed:\n\(formatedDictionary)\n")

结果

enter image description here

Swift 5 xcode 10.3:

po print(<your Plist container>)

调试时,将符合 Codable Protocol 的结构输出到控制台
使用 json 格式。

extension Encodable {
var jsonData: Data? {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
return try? encoder.encode(self)
}
}


extension Encodable where Self: CustomDebugStringConvertible {
var debugDescription: String {
if let data = self.jsonData,
let string = String(data: data, encoding: .utf8) {
return string
}
return "can not convert to json string"
}
}

可转换

struct Test: Codable, CustomDebugStringConvertible {
let a: String
let b: Int
}


let t = Test(a: "test string", b: 30)

调试打印结构调试打印结构

(lldb) p print(t)
{
"a" : "test string",
"b" : 30
}

Pretty print from Data object:

let jsonObj = try JSONSerialization.jsonObject(with: data, options: [])
let jsonData = try JSONSerialization.data(withJSONObject: jsonObj, options: [.prettyPrinted])
print(String(data: jsonData, encoding: .utf8)!)

根据我的其他答案调整 给你

使用 LLDB 别名打印 JSON 解决方案

Something 不需要代码 something

  • 要获得一个不错的 json 格式(缩进、换行等) ,可以通过在 XCode (来源)中的 lldb 终端中运行这个命令来定义 lldb 别名:
command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'
  • 上面的命令仅在当前 XCode 会话期间有效。为了避免每次打开 XCode 时重新定义别名,请在 macOS 终端中运行以下命令。它将把上面定义的别名追加到 ~/.lldbinit,LLDB 将在每次 XCode 启动时加载该别名:
echo "command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'" >> ~/.lldbinit
  • 这将创建 pjson别名,您可以在 XCode 中的 lldb 终端中使用该别名:
pjson object

比较下列 Swift 对象的输出:

// Using Any? to demo optional & arbitrary Type
let dictionary: Any? = [
"embedded": [
"JustForTheSakeOfTheDemo": 42
],
"A" : "alfa",
"B" : "bravo",
"C" : "charlie",
"D" : "delta",
"E" : "echo",
"F" : "foxtrot"
]

Something pjson dictionary的输出

{
"F" : "foxtrot",
"D" : "delta",
"embedded" : {
"JustForTheSakeOfTheDemo" : 42
},
"E" : "echo",
"A" : "alfa",
"C" : "charlie",
"B" : "bravo"
}

Something p dictionary的输出

(Any?) $R0 = 7 key/value pairs {
[0] = {
key = "F"
value = "foxtrot"
}
[1] = {
key = "D"
value = "delta"
}
[2] = {
key = "embedded"
value = 1 key/value pair {
[0] = (key = "JustForTheSakeOfTheDemo", value = 42)
}
}
[3] = {
key = "E"
value = "echo"
}
[4] = {
key = "A"
value = "alfa"
}
[5] = {
key = "C"
value = "charlie"
}
[6] = {
key = "B"
value = "bravo"
}
}

Something p (dictionary as! NSDictionary)的输出

(NSDictionary) $R18 = 0x0000000281e89710 {
ObjectiveC.NSObject = {
base__SwiftNativeNSDictionaryBase@0 = {
baseNSDictionary@0 = {
NSObject = {
isa = Swift._SwiftDeferredNSDictionary<Swift.String, Any> with unmangled suffix "$"
}
}
}
}
}

Something po dictionary的输出

▿ Optional<Any>
▿ some : 7 elements
▿ 0 : 2 elements
- key : "F"
- value : "foxtrot"
▿ 1 : 2 elements
- key : "D"
- value : "delta"
▿ 2 : 2 elements
- key : "embedded"
▿ value : 1 element
▿ 0 : 2 elements
- key : "JustForTheSakeOfTheDemo"
- value : 42
▿ 3 : 2 elements
- key : "E"
- value : "echo"
▿ 4 : 2 elements
- key : "A"
- value : "alfa"
▿ 5 : 2 elements
- key : "C"
- value : "charlie"
▿ 6 : 2 elements
- key : "B"
- value : "bravo"

Something po print(dictionary)的输出

Optional(["F": "foxtrot", "D": "delta", "embedded": ["JustForTheSakeOfTheDemo": 42], "E": "echo", "A": "alfa", "C": "charlie", "B": "bravo"])
 print("{")
for (key,value) in dictionary {
if let stringValue = value as? String {
print("\"\(key)\" = \"\(stringValue.description)\",")
}else{
print("\"\(key)\" = \(value),")
}
}
print("}")