我怎样才能轻松地看到符合 `Codable` 协议的对象的 JSON 输出
How can I easily see the JSON output from my objects that conform to the `Codable` Protocol
我使用 Codable 协议处理很多 serialize/deserialize 到 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"
}
我厌倦了每次需要时都编写相同的六行代码。有没有更简单的方法?
没有一种常用的方法可以将 Codable
对象图转换为 "pretty" 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)
并以 "pretty printed" 形式显示 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 进行格式化
我建议创建一个静态编码器,这样您就不会在每次调用时都创建一个新的编码器 属性:
extension JSONEncoder {
static let shared = JSONEncoder()
static let iso8601 = JSONEncoder(dateEncodingStrategy: .iso8601)
static let iso8601PrettyPrinted = JSONEncoder(dateEncodingStrategy: .iso8601, outputFormatting: .prettyPrinted)
}
extension JSONEncoder {
convenience init(dateEncodingStrategy: DateEncodingStrategy,
outputFormatting: OutputFormatting = [],
keyEncodingStrategy: KeyEncodingStrategy = .useDefaultKeys) {
self.init()
self.dateEncodingStrategy = dateEncodingStrategy
self.outputFormatting = outputFormatting
self.keyEncodingStrategy = keyEncodingStrategy
}
}
考虑到您是在 Encodable 扩展中调用此方法,您可以强制尝试!。您还可以强制从数据转换为字符串:
extension Encodable {
func data(using encoder: JSONEncoder = .iso8601) throws -> Data {
try encoder.encode(self)
}
func dataPrettyPrinted() throws -> Data {
try JSONEncoder.iso8601PrettyPrinted.encode(self)
}
// edit if you need the data using a custom date formatter
func dataDateFormatted(with dateFormatter: DateFormatter) throws -> Data {
JSONEncoder.shared.dateEncodingStrategy = .formatted(dateFormatter)
return try JSONEncoder.shared.encode(self)
}
func json() throws -> String {
String(data: try data(), encoding: .utf8) ?? ""
}
func jsonPrettyPrinted() throws -> String {
String(data: try dataPrettyPrinted(), encoding: .utf8) ?? ""
}
func jsonDateFormatted(with dateFormatter: DateFormatter) throws -> String {
return String(data: try 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)
try! print("JSON\n=================\n", foo.json(), terminator: "\n\n")
try! print("JSONPrettyPrinted\n=================\n", foo.jsonPrettyPrinted(), terminator: "\n\n")
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .long
try! print("JSONDateFormatted\n=================\n", foo.jsonDateFormatted(with: dateFormatter))
这将打印
JSON
=================
{"date":"2020-11-06T20:22:55Z","bar":{"name":"Fred"},"string1":"string1","val":42,"string2":"string2"}
JSONPrettyPrinted
=================
{
"date" : "2020-11-06T20:22:55Z",
"bar" : {
"name" : "Fred"
},
"string1" : "string1",
"val" : 42,
"string2" : "string2"
}
JSONDateFormatted
=================
{"date":"6 November 2020","bar":{"name":"Fred"},"string1":"string1","val":42,"string2":"string2"}
我使用 Codable 协议处理很多 serialize/deserialize 到 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"
}
我厌倦了每次需要时都编写相同的六行代码。有没有更简单的方法?
没有一种常用的方法可以将 Codable
对象图转换为 "pretty" 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)
并以 "pretty printed" 形式显示 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 进行格式化
我建议创建一个静态编码器,这样您就不会在每次调用时都创建一个新的编码器 属性:
extension JSONEncoder {
static let shared = JSONEncoder()
static let iso8601 = JSONEncoder(dateEncodingStrategy: .iso8601)
static let iso8601PrettyPrinted = JSONEncoder(dateEncodingStrategy: .iso8601, outputFormatting: .prettyPrinted)
}
extension JSONEncoder {
convenience init(dateEncodingStrategy: DateEncodingStrategy,
outputFormatting: OutputFormatting = [],
keyEncodingStrategy: KeyEncodingStrategy = .useDefaultKeys) {
self.init()
self.dateEncodingStrategy = dateEncodingStrategy
self.outputFormatting = outputFormatting
self.keyEncodingStrategy = keyEncodingStrategy
}
}
考虑到您是在 Encodable 扩展中调用此方法,您可以强制尝试!。您还可以强制从数据转换为字符串:
extension Encodable {
func data(using encoder: JSONEncoder = .iso8601) throws -> Data {
try encoder.encode(self)
}
func dataPrettyPrinted() throws -> Data {
try JSONEncoder.iso8601PrettyPrinted.encode(self)
}
// edit if you need the data using a custom date formatter
func dataDateFormatted(with dateFormatter: DateFormatter) throws -> Data {
JSONEncoder.shared.dateEncodingStrategy = .formatted(dateFormatter)
return try JSONEncoder.shared.encode(self)
}
func json() throws -> String {
String(data: try data(), encoding: .utf8) ?? ""
}
func jsonPrettyPrinted() throws -> String {
String(data: try dataPrettyPrinted(), encoding: .utf8) ?? ""
}
func jsonDateFormatted(with dateFormatter: DateFormatter) throws -> String {
return String(data: try 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)
try! print("JSON\n=================\n", foo.json(), terminator: "\n\n")
try! print("JSONPrettyPrinted\n=================\n", foo.jsonPrettyPrinted(), terminator: "\n\n")
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .long
try! print("JSONDateFormatted\n=================\n", foo.jsonDateFormatted(with: dateFormatter))
这将打印
JSON
=================
{"date":"2020-11-06T20:22:55Z","bar":{"name":"Fred"},"string1":"string1","val":42,"string2":"string2"}
JSONPrettyPrinted
=================
{
"date" : "2020-11-06T20:22:55Z",
"bar" : {
"name" : "Fred"
},
"string1" : "string1",
"val" : 42,
"string2" : "string2"
}
JSONDateFormatted
=================
{"date":"6 November 2020","bar":{"name":"Fred"},"string1":"string1","val":42,"string2":"string2"}