Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我怎样才能轻松地看到符合“Codable”协议的对象的JSON输出_Json_Swift_Pretty Print_Codable - Fatal编程技术网

我怎样才能轻松地看到符合“Codable”协议的对象的JSON输出

我怎样才能轻松地看到符合“Codable”协议的对象的JSON输出,json,swift,pretty-print,codable,Json,Swift,Pretty Print,Codable,我使用可编码协议处理了大量序列化/反序列化为JSON的对象 创建一个jsonecoder,将其设置为漂亮的打印,将对象转换为JSON,然后将其转换为字符串并不难,但似乎需要大量的工作。有没有一种简单的方式可以说“请给我看看这个对象的JSON输出?” 编辑: 例如,假设我有以下结构: struct Foo: Codable { let string1: String? let string2: String? let date: Date let val: Int

我使用可编码协议处理了大量序列化/反序列化为JSON的对象

创建一个
jsonecoder
,将其设置为漂亮的打印,将对象转换为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字符串,但是定义一个协议来实现这一点非常容易,因此您不必反复编写相同的转换代码

您只需创建可编码协议的扩展,如下所示:

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格式化对象图中的日期。我建议您创建一个静态编码器,这样您就不会每次调用该属性时都创建一个新的编码器:

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


考虑到您正在可编码扩展内调用此方法,您可以强制尝试!。您还可以强制将数据转换为字符串:

extension Encodable {
    func data(using encoder: JSONEncoder = .iso8601) throws -> Data {
        try encoder.encode(self)
    }
    func dataPrettyPrinted() throws -> Data {
        try JSONEncoder.iso8601PrittyPrinted.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
}

这会打印出来

JSON
=========================
{“日期”:“2020-11-06T20:22:55Z”,“酒吧”:{“姓名”:“Fred”},“string1”:“string1”,“val”:42,“string2”:“string2”}

Jsonprettypted
=========================
{
“日期”:“2020-11-06T20:22:55Z”,
“酒吧”:{
“姓名”:“弗雷德”
},
“string1”:“string1”,
“val”:42,
“string2”:“string2”
}

JSONDateFormatted
=========================
{“日期”:“2020年11月6日”,“酒吧”:{“姓名”:“Fred”},“string1”:“string1”,“val”:42,“string2”:“string2”}


抛出而不是返回字符串可能是个好主意,这样就不会传递到后端。如何向扩展添加静态变量?当我尝试那样做时,编译器会抱怨。另外,我没有看到初始化器
jsonecoder.init(dateEncodingStrategy:outputFormatting:)
@Duncan我使用的是最新的AppStore Xcode版本Swift 4.1那么你可以发布整个游乐场吗?方便初始化器完成了。(投票)您唯一没有做的就是允许用户指定自定义日期格式化程序/日期编码策略。
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))