将 swift 结构转换为 json 字符串

Posted

技术标签:

【中文标题】将 swift 结构转换为 json 字符串【英文标题】:Convert swift struct to json string 【发布时间】:2018-03-05 20:45:55 【问题描述】:

我正在尝试将我的 swift 结构转换为 json 格式。似乎有很多这样的问题,但到目前为止,没有一个解决方案对我有用。

这是我的结构

struct Rec : Codable 
    var name:String
    var time:Int
    var values:[String]

    var jsonRepresentation : String 
        return """
            
                "name":"\(name)",
                "time":\(time),
                "values":\(values)
            
        """
    

这里是外部api接收的json格式。


    "op" : "delete",
     "rec":  
        "name" : "some string",
        "time":200,

        "values": [ 
            "127.0.0.1"
        ]
    

这是我创建 HTTP 请求的函数

 private func createPatchRequest(op: String, url: URL, rec: Rec) throws -> URLRequest 
    let dictionary: [String: String] = [
        "op":op,
        "rec":rec.jsonRepresentation
    ]

    let jsonData = try JSONEncoder().encode(dictionary)

    var request = URLRequest(url: url)

    request.httpMethod = "PATCH"
    request.httpBody = jsonData
    request.addValue("application/json", forHTTPHeaderField:"Content-Type")

    return request

我总是得到 400,我相信 swift 没有正确编码我的 json。我尝试了邮递员的请求,效果很好!

这是邮递员的样子


    "op" : "delete",
    "rec":  
        "name" : "some string",
        "time":600,
        "values": [ 
            "127.0.0.1"
        ]
    

有什么想法吗?谢谢!

【问题讨论】:

哎呀。刚刚编辑它。它的“rec”一路 由于你的结构是Codable,你不必做奇怪的手动创建jsonRepresentation的事情然后编码它,你可以直接调用JSONEncoder().encode(rec)。您需要创建一个具有 oprec 属性的包装请求结构并对其进行编码 【参考方案1】:

问题在于 API 期望 rec 是 JSON 对象,但您将 Rec 作为 JSON 对象的字符串表示形式发送。即这是您发送的 JSON:


  "rec": "\n\"name\":\"some string\",\n\"time\":1,\n\"values\":[\"127.0.0.1\"]\n",
  "op": "delete"

理想的方法是使用嵌套的Rec 结构创建Codable PatchRequest 并对其进行编码。您可以在 Playground 上尝试以下 sn-p

struct Rec : Codable 
    var name:String
    var time:Int
    var values:[String]

struct PatchRequest : Codable
    var op: String
    var rec: Rec


let rec = Rec(name: "some string",time: 600,values: ["127.0.0.1"])
let requst = PatchRequest(op: "delete",rec: rec)

let jsonData = try JSONEncoder().encode(requst)
let jsonString = String(data: jsonData, encoding: .utf8) 

这具有减少 API 方法所需的参数数量并使代码整体更简洁的额外好处:

private func createPatchRequest(url: URL, patchRequest: PatchReuest) throws -> URLRequest 
    let jsonData = try JSONEncoder().encode(patchRequest)

    var request = URLRequest(url: url)

    request.httpMethod = "PATCH"
    request.httpBody = jsonData
    request.addValue("application/json", forHTTPHeaderField:"Content-Type")

    return request

最后,我建议在你的结构中使用let 而不是var,除非绝对必要。

【讨论】:

这非常有效。有没有可靠的方法将字符串直接转换为 json?我认为我的jsonRepresentation 功能不错。甚至打印出来,看起来还不错。但它不起作用。 理想情况下,如果 API 请求 JSONObject,您应该创建一个与该对象对应的结构并直接使用 JSONEncoder 对其进行编码。尝试通过格式化字符串来构造 json 可能会导致奇怪的错误,例如在您的情况下,您发送的是 JSON 对象的字符串表示,而不是实际的 json 对象。 @SomeGuyFortune 你的jsonRepresentation 确实可以工作(它工作的事实是通过改变,永远不要自己编码JSON!)但是一旦你把它放入字典,它就不能工作,因为您正在尝试使用 JSON 字符串对 JSON 进行编码。【参考方案2】:

您的 jsonRepresentation 是一个字符串,但应该是一个字典。以这种方式更新您的结构:

struct Rec : Codable 
var name:String
var time:Int
var values:[String]

var jsonRepresentation: [String: Any] 
    return [
        "name": name,
        "time": time,
        "values": values
    ]
  

希望对您有所帮助!请让我知道它是否有效。

【讨论】:

另外,他应该在任何地方删除\(...),直接使用nametimevalues!当您需要一个字符串数组时,值仍在转换为 String 这比我的干净多了。但似乎更好的方法是创建一个包装结构,它也应该是可编码的。这样 swift 可以更好地将其编码为 json。 ` let jsonData = try JSONEncoder().encode(someEncodableStructObject)`

以上是关于将 swift 结构转换为 json 字符串的主要内容,如果未能解决你的问题,请参考以下文章

使用 Swift 4 Decodable 将字符串 JSON 响应转换为布尔值

为啥 Alamofire 4.4.0 将 JSON 字符串转换为转义的 JSON 字符串(Swift 3)?

使用 Swift 将 JSON 字符串转换为 NSDictionary

将 swift 对象转换为 JSON 字符串

使用大引号时,将字符串 JSON 转换为 Swift 中的字典

将 JSON 字符串 UTF8 转换为 NSDictionary Swift