如何在Swift 4.2中将JSON转换为Codable?

时间:2019-02-23 13:50:14

标签: json swift codable

我正在使用Xcode 10.1和Swift 4.2。当我尝试将JSON响应转换为Codable类时,它给出了一个错误Expected to decode Array<Any> but found a string/data instead.

我的实际JSON响应来自API。

{
    "d": "[{\"Data\":{\"mcustomer\":[{\"slno\":1000000040.0,\"fstname\":null}]},\"Status\":true}]"
} 

我的模特就是这样

class MainData: Codable{

    var d: [SubData]

}

class SubData : Codable {


    var Data : Customer

    var Status : Bool?

}


class Customer : Codable {

    var mcustomer : [Detail]

}


class Detail : Codable {

    var slno : Double?

    var fstname : String?

}

我正在使用JSONDecoder()对此模型进行解码

let decoder = JSONDecoder()

let deco = try decoder.decode(MainData.self, from: data)

但是,我无法将此Json解码为我的模型。

3 个答案:

答案 0 :(得分:1)

您的API错误。您在json中的数组不应在其两端加上引号。否则,您将声明键"d"的值为字符串

"[...]"

[...]


建议:

  • 变量和常量应以小写大写字母开头。否则,例如,您的Data属性将导致与Data类型的混淆。要在解码时重命名,可以使用CodingKeys
  • 如果您不需要对模型进行编码,则只需实施Decodable协议
  • 您可以在模型中使用struct代替class

答案 1 :(得分:0)

顶级JSON对象是具有键“ d”和 string 值的字典,代表另一个JSON对象(有时称为“嵌套JSON”)。如果无法更改服务器API,则必须分两个步骤进行解码:

  • 解码顶级词典。
  • 从第一步中获得的字符串中解码JSON对象。

结合罗伯特(Robert)关于命名CodingKeys并使用struct的建议,它看起来像这样:

struct MainData: Codable {
    let d: String
}

struct SubData : Codable {
    let data : Customer
    let status : Bool

    enum CodingKeys: String, CodingKey {
        case data = "Data"
        case status = "Status"
    }
}

struct Customer : Codable {
    let mcustomer : [Detail]
}

struct Detail : Codable {
    let slno : Double
    let fstname : String?
}

do {
    let mainData = try JSONDecoder().decode(MainData.self, from: data)
    let subData = try JSONDecoder().decode([SubData].self, from: Data(mainData.d.utf8))

    print(subData)

} catch {
    print(error)
}

答案 2 :(得分:0)

要使您的解决方案正常工作,JSON响应必须采用以下格式

let json = """
  {
  "d": [
    {
      "Data": {
        "mcustomer": [
          {
            "slno": 1000000040,
            "fstname": null
          }
        ]
      },
      "Status": true
    }
  ]
}
"""

但是,正如您所看到的,您得到的JSON响应与您期望的完全不同。您需要要求更改响应,或者需要更改模型。