如何从符合`Codable`协议的对象中轻松查看JSON输出

问题描述 投票:2回答:2

我处理了许多使用Codable协议对JSON进行序列化/反序列化的对象。

创建一个JSONEncoder,将其设置为漂亮打印,将对象转换为JSON,然后将其转换为字符串并不难,但似乎需要做很多工作。有没有一种简单的方法可以说“请告诉我这个对象的JSON输出?”

编辑:

比方说,我有以下结构:

struct Foo: Codable {
    let string1: String?
    let string2: String?
    let date: Date
    let val: Int
    let aBar: Bar
}

struct Bar: Codable {
    let name: String
}

并说我创建了一个Foo对象:

let aBar = Bar(name: "Fred")
let aFoo = Foo(string1: "string1", string2: "string2", date: Date(), val: 42, aBar: aBar)

我可以使用六行自定义代码打印出来:

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
guard let data = try? encoder.encode(aFoo),
    let output = String(data: data, encoding: .utf8)
    else { fatalError( "Error converting \(aFoo) to JSON string") }
print("JSON string = \(output)")

哪个会给出输出:

JSON string = {
  "date" : 557547327.56354201,
  "aBar" : {
    "name" : "Fred"
  },
  "string1" : "string1",
  "val" : 42,
  "string2" : "string2"
}

我厌倦了每次需要时编写相同的六行代码。有没有更简单的方法?

json swift pretty-print codable
2个回答
2
投票

我建议创建一个静态编码器,这样每次调用该属性时都不会创建新的编码器:

extension JSONEncoder {

    static let shared = JSONEncoder()
    static let iso8601 = JSONEncoder(dateEncodingStrategy: .iso8601)
    static let iso8601PrittyPrinted = JSONEncoder(dateEncodingStrategy: .iso8601, outputFormatting: .prettyPrinted)

    convenience init(dateEncodingStrategy: DateEncodingStrategy, outputFormatting: OutputFormatting? = nil) {
        self.init()
        self.dateEncodingStrategy = dateEncodingStrategy
        self.outputFormatting = outputFormatting ?? []
    }
}

考虑到您在Encodable扩展中调用此方法,您可以强制尝试!您还可以强制从数据转换为字符串:

extension Encodable {
    var data: Data {
        return try! JSONEncoder.iso8601.encode(self)
    }
    var dataPrettyPrinted: Data {
        return try! JSONEncoder.iso8601PrittyPrinted.encode(self)
    }
    // edit if you need the data using a custom date formatter
    func dataDateFormatted(with dateFormatter: DateFormatter) -> Data {
        JSONEncoder.shared.dateEncodingStrategy = .formatted(dateFormatter)
        return try! JSONEncoder.shared.encode(self)
    }
    var json: String {
        return String(data: data, encoding: .utf8)!
    }
    var jsonPrettyPrinted: String {
        return String(data: dataPrettyPrinted, encoding: .utf8)!
    }
    func jsonDateFormatted(with dateFormatter: DateFormatter) -> String {
        return String(data: dataDateFormatted(with: dateFormatter), encoding: .utf8)!
    }
}

游乐场测试

struct Foo: Codable {
    let string1: String
    let string2: String
    let date: Date
    let val: Int
    let bar: Bar
}
struct Bar: Codable {
    let name: String
}

let bar = Bar(name: "Fred")
let foo = Foo(string1: "string1", string2: "string2", date: Date(), val: 42, bar: bar)

print("json\n====\n\n", foo.json)
print()
print("jsonPrettyPrinted\n=================\n\n", foo.jsonPrettyPrinted)

print()
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .long
print("jsonDateFormatted\n=================\n\n", foo.jsonDateFormatted(with: dateFormatter))

这将打印

/*
 json
 ====

 {"date":"2018-09-02T15:35:37Z","bar":{"name":"Fred"},"string1":"string1","val":42,"string2":"string2"}

 jsonPrettyPrinted
 =================

 {
 "date" : "2018-09-02T15:35:37Z",
 "bar" : {
 "name" : "Fred"
 },
 "string1" : "string1",
 "val" : 42,
 "string2" : "string2"
 }

 jsonDateFormatted
 =================

 {"date":"September 2, 2018","bar":{"name":"Fred"},"string1":"string1","val":42,"string2":"string2"}

 */

Sample


1
投票

没有一种方法可以将Codable对象图转换为“漂亮的”JSON字符串,但是定义一个协议很容易,所以你不要反复编写相同的转换代码。

您可以简单地创建Encodable协议的扩展,如下所示:

extension Encodable {
    var prettyJSON: String {
        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        guard let data = try? encoder.encode(self),
            let output = String(data: data, encoding: .utf8)
            else { return "Error converting \(self) to JSON string" }
        return output
    }
}

然后是任何JSON对象

print(myJSONobject.prettyJSON)

它以“漂亮打印”的形式显示JSON文本。

以上不会做的一件事是支持日期的自定义格式。为此,我们可以将prettyJSON修改为函数而不是计算属性,其中它将可选的DateFormatter作为参数,其默认值为nil

extension Encodable {
    func prettyJSON(formatter: DateFormatter? = nil) -> String {
        let encoder = JSONEncoder()
        if let formatter = formatter {
            encoder.dateEncodingStrategy = .formatted(formatter)
        }
        encoder.outputFormatting = .prettyPrinted
        guard let data = try? encoder.encode(self),
            let output = String(data: data, encoding: .utf8)
            else { return "Error converting \(self) to JSON string" }
        return output
    }
}

然后你可以像上面一样使用它,除了你需要在prettyJSON之后添加括号,例如

print(myJSONobject.prettyJSON())

该表单忽略新的DateFormatter参数,并将输出与上面相同的JSON字符串。但是,如果您有自定义日期格式化程序:

var formatter = DateFormatter()
formatter.dateFormat = "MM-dd-yyyy HH:mm:ss"

print(myJSONobject.prettyJSON(formatter: formatter))

然后,使用指定的DateFormatter格式化对象图中的日期

© www.soinside.com 2019 - 2024. All rights reserved.