有没有一种方法可以将Swift词典漂亮地打印到控制台上?


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

在控制台上打印出以下内容:

{
    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)

在控制台上打印出以下内容:

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

在Swift中,有没有一种方法可以将其带到漂亮的印刷字典中,其中每个键值对都占一行?


7
dump例如,如果目标是检查字典,则可以使用。stackoverflow.com/documentation/swift/3966/logging-in-swift/...
埃里克·绫

13
print(dictionary as! NSDictionary) 把戏?
BaseZen

我真的使用了dump()建议,因为它不需要编写任何代码或强制转换。@EricAya,如果您发表带有此评论的答案,我会将其标记为答案。
Toland Hon

1
@TolandHon完成。我已经用输出示例给出了答案。
埃里克·艾雅

Answers:


99

例如,如果目标是检查字典,则可以使用dumpdump是Swift标准库的一部分。

用法:

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

dump(dictionary)

输出:

在此处输入图片说明


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

数组的详细视图:

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

印刷品:

▿4个元素
-[0]:乔
-[1]:简
-[2]:吉姆
-[3]:乔伊斯

对于字典:

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

印刷品:

▿3个键/值对
▿[0]:(2个元素)
-. 0 :bar
-.1:
33▿[1]:(2个元素)
-.0:baz
-.1:
42▿[2]:( 2个元素)
-.0:foo
-.1:10

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

第一个参数没有标签。

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

dump(attributes, name: "mirroring")

印刷品:

▿镜像:3个键/值对
▿[0] :( 2个元素)
-. 0 :bar
-.1:
33▿[1] :( 2个元素)
-.0:baz
-.1:
42▿[2] :(2个元素)
-.0:foo
-.1:10

您也可以选择仅使用来打印特定数量的项目maxItems:,使用来解析对象达一定深度maxDepth:,并使用来更改打印对象的压痕indent:


5
这不是打印好的JSON,这只是将变量转储到控制台中-无效的JSON。尽管它确实符合OP的需求,但我认为该问题需要重新措辞以与此匹配。
詹姆斯·沃尔夫

4
@JamesWolfeThis is not pretty printed JSON没有人说过。OP询问了漂亮的Swift字典打印-除了几个离题的回答者,没有人谈论JSON。OP的问题根本不是关于JSON的。
埃里克·艾雅

@JamesWolfe也请不要更改问题。那将是故意破坏。问题很明显,与JSON无关。不要仅仅因为某些答案在谈论其他问题而更改问题。谢谢。
埃里克·艾雅

112

对我来说,将字典强制转换为“ AnyObject”是最简单的解决方案:

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

这是控制台输出

对我来说,这比转储选项更容易阅读,但是请注意,它不会为您提供键值的总数。


11
这是比转储更好的绝妙方法
AbdelHady

109

溶液

对于那些想要在控制台中看到没有转义序列的Dictionary为JSON的人,这是一种简单的方法

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


1
由于是表达式而不是对象,因此应为“ p”而不是“ po”。但是,非常感谢您提供此解决方案!对我来说效果很好
亚历山德罗·弗朗奇

@AlessandroFrancucci有关系吗?该命令似乎以任何一种方式执行相同的操作。
nickjwallin

现在,两种方法都可以正常工作。但是在做“印刷”之前对我没有用。(po表示打印对象...。如果您以后进行打印而不是对象恕我直言,这会有些混乱)
Alessandro Francucci

太棒了!正是我需要通过PushNotification很好地打印userInfo所需的内容
carmen_munich

选中此注释可在lldb别名中利用此注释,因此您不必每次都键入它!
agirault

36

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

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

输出量

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

1
这应该是最佳答案。完美的作品!
Yuri Doubov

或成为“甚至更具功能性” ... dictionary.map {“($ 0):($ 1)”} .forEach(print)(舌头讽刺评论)
Jon Willis

3
这适用于OP的[String: String]字典,但不适用于[AnyHashable: Any]字典,在字典中,如果值是字典,则返回到Swift的非精美打印。
Christopher Pickslay '18

我有本书打上这个answer🙂,因为我依然无法记起这句法🙄
尼廷Alabur

29

仅出于调试目的,我会将Array或Dictionary转换为漂亮打印的json:

public extension Collection {

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

然后:

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
}

bLog这里是什么?
Nitesh

@Nitesh bLog是我编写的带有backtrace的简单自定义记录器,使用print()编辑。
Marco M

最漂亮的解决方案。
Denis Kutlubaev

如果您希望避免在每个项目中添加该代码段,则可以将该代码与lldb别名结合使用,以在调试终端中轻松计算json(在此处详细说明)。
agirault

14

我不会考虑这里提供的许多答案,因为它们是真正漂亮的打印JSON,因为当您将结果传递到JSON验证程序中时,结果是无效的(通常是由于代码包括“ =”而不是“:”)。

我发现最简单的方法就是使用漂亮的打印选项将JSON对象转换为数据,然后使用结果数据打印字符串。

这是一个例子:

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

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

结果:

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

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

我相信,尽管OP不要求提供JSON,但它是一个可行的答案,因为与xcode / swift散布到控制台中的可怕格式相比,它是一种更具可读性的数据格式。


1
谢谢,这样,我就可以通过e let jsonData = try! JSONSerialization.data(withJSONObject: response, options: .prettyPrinted);if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }
BangOperator

1
这很棒!您可以将此代码与lldb别名结合使用,以轻松地在调试终端中计算json(在此处查看详细信息)。
agirault

5

您可以只使用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

1
为什么将prettyprint设为var而不是函数,是有原因的?
Hayden Holligan'8

老实说,我认为这并不重要(我可能是错的)。但是,如果您经常使用它,则键入的次数会更少。但是请提出一个有趣的问题。
Asdrubal

3
由于已经存在descriptiondebugDescription,因此调用varprettyDescription并返回格式化的字符串可能更合适。
Toland Hon

5

将Swift字典转换为json并返回的方法是最干净的。我使用Facebook的凿子,该凿子具有pjson命令来打印Swift字典。例如:

(lldb) pjson dict as NSDictionary

这应该漂亮地打印字典。这是一种已经建议的更清洁的方法。PS目前,您必须将dict转换为NSDictionary,因为Objective-C运行时无法理解Swift字典。我已经提出了凿子的公关以摆脱该限制。

更新:我的PR被接受了。现在,您可以使用psjson命令而不是上面提到的pjson


4

对于Swift 3(并以@Jalakoo的出色回答为基础),进行以下Dictionary扩展:

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

然后使用此方法以一种漂亮的方式(优于)打印任何层次的字典:dump()

print(dictionary!.prettyPrint)

4

细节

  • 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")

结果

在此处输入图片说明


2

根据我在这里的其他答案进行调整。

使用LLDB别名的PrettyPrint JSON解决方案

无需代码

  • 要获得不错的json格式(缩进,换行符等),您可以通过在lldb终端()中运行以下命令来定义lldb别名:
command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'
  • 您可能不想每次打开XCode时都重新定义别名,因此运行以下命令将别名定义附加到~/.lldbinit
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"
]

of输出 pjson dictionary

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

of输出 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"
  }
}

of输出 p (dictionary as! NSDictionary)

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

of输出 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 : 423 : 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"

of输出 po print(dictionary)

Optional(["F": "foxtrot", "D": "delta", "embedded": ["JustForTheSakeOfTheDemo": 42], "E": "echo", "A": "alfa", "C": "charlie", "B": "bravo"])


1

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

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"
     }
}

strcut符合CustomDebugStringConvertible

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
}

1

从数据对象漂亮打印:

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

1
这很棒!您可以将此代码与lldb别名结合使用,以轻松地在调试终端中计算json(在此处查看详细信息)。
agirault

0

怎么样:

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)

0
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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.