无法使用Codable和Alamofire 3.0解析数据

时间:2019-01-08 18:22:55

标签: ios swift alamofire codable

我无法使用可解码和alamofire 3.0解析json响应数据。我收到以下错误。

  

错误keyNotFound(CodingKeys(stringValue:“ server_time”,intValue:nil),Swift.DecodingError.Context(codingPath:[],debugDescription:“与键CodingKeys(stringValue:\” server_time \“,intValue:没有关联的值: nil)(\“ server_time \”)。“,底层错误:nil))

这是我的代码。

解析代码

  struct NewAucListJSON_Modal : Codable
{
    let serverTime : String?
    let error: Bool?

    let display_name: String?
    let list_id: Int?
    let fk_com_id: Int?

    let numFound : Int?

    enum CodingKeys: String, CodingKey {

        case data = "data"
        case response = "response"
        case numFound = "numFound"
        case docs = "docs"

        case display_name = "display_name", list_id = "list_id", fk_com_id = "fk_com_id"

        case serverTime = "server_time"
        case error = "error"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let response_data = try container.nestedContainer(keyedBy:
            CodingKeys.self, forKey: .data)

        self.serverTime = try response_data.decode(String.self, forKey: .serverTime)
        self.error = try response_data.decode(Bool.self, forKey: .error)

        let response = try response_data.nestedContainer(keyedBy: CodingKeys.self, forKey: .response)
        let docs = try response.nestedContainer(keyedBy: CodingKeys.self, forKey: .docs)

        display_name = try docs.decode(String.self, forKey: .display_name)
        list_id = try docs.decode(Int.self, forKey: .list_id)
        fk_com_id = try docs.decode(Int.self, forKey: .fk_com_id)

        self.numFound = try response.decode(Int.self, forKey: .numFound)

    }
    func encode(to encoder: Encoder) throws {

    }
}

JSON响应

{
    "data": {
        "responseHeader": {
            "status": 0,
            "QTime": 0,
            "params": {
                "q": "type:*",
                "front_id:[1 TO 7] OR market:Nafed": "",
                "fq": ["status:[100 TO 190]", "!template_id:(\"-40\" \"-50\")"],
                "sort": "status DESC"
            }
        },
        "response": {
            "numFound": 7,
            "start": 0,
            "docs": [{
                "fk_com_id": 6,
                "list_id": 3089,
                "display_name": "GDSMP-3089"
            }, {
                "fk_com_id": 6,
                "list_id": 3089,
                "display_name": "GDSMP-3089"
            }, {
                "fk_com_id": 6,
                "list_id": 3089,
                "display_name": "GDSMP-3089"
            }, {
                "fk_com_id": 6,
                "list_id": 3089,
                "display_name": "GDSMP-3089"
            }, {
                "fk_com_id": 6,
                "list_id": 3089,
                "display_name": "GDSMP-3089"
            }, {
                "fk_com_id": 6,
                "list_id": 3089,
                "display_name": "GDSMP-3089"
            }, {
                "fk_com_id": 6,
                "list_id": 3089,
                "display_name": "GDSMP-3089"
            }]
        }
    },
    "error": false,
    "message": "Data Listed.",
    "recordsFiltered": 0,
    "recordsTotal": 0,
    "server_time": "2019-01-08 15:03:28"
}

如果我对嵌套容器使用了不同的结构,则解析代码将变为:

   struct AucListInfo : Codable
{
    let docs : [AucListDoc]
    let numFound : Int

    enum CodingKeys: String, CodingKey {
        case response = "response"
        case docs = "docs"
        case numFound = "numFound"
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        var response = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .response)
        try response.encode(self.docs, forKey: .docs)
        try response.encode(self.numFound, forKey: .numFound)
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let response = try container.nestedContainer(keyedBy:
            CodingKeys.self, forKey: .response)
        self.docs = try response.decode([AucListDoc].self, forKey: .docs)
        self.numFound = try response.decode(Int.self, forKey: .numFound)
    }
}

struct AucListDoc : Codable
{
    let display_name: String?
    let list_id: Int?
    let fk_com_id: Int?

    private enum CodingKeys: String, CodingKey {

        case display_name = "display_name", list_id = "list_id", fk_com_id = "fk_com_id"
    }

    init(display_name: String, list_id: Int, fk_com_id: Int) {

        self.display_name = display_name
        self.list_id = list_id
        self.fk_com_id = fk_com_id

    }

    init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: CodingKeys.self)

        display_name = try container.decode(String.self, forKey: .display_name)
        list_id = try container.decode(Int.self, forKey: .list_id)
        fk_com_id = try container.decode(Int.self, forKey: .fk_com_id)

    }
}

struct AucListJSON_Modal: Codable
{
//    let data: AucListResponse?
    let server_time : String
    let error: Bool
    let response : AucListInfo

    enum CodingKeys: String, CodingKey {
        case data = "data"
        case response = "response"
        case server_time = "server_time"
        case error = "error"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let response = try container.nestedContainer(keyedBy:
            CodingKeys.self, forKey: .data)
        self.server_time = try response.decode(String.self, forKey: .server_time)
        self.error = try response.decode(Bool.self, forKey: .error)
        self.response = try response.decode(AucListInfo.self, forKey: .response)
    }
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        var response = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .data)
        try response.encode(self.server_time, forKey: .server_time)
        try response.encode(self.error, forKey: .error)
        try response.encode(self.response, forKey: .response)
    }
}
  

请帮助我解决错误

1 个答案:

答案 0 :(得分:0)

不确定我是否正确理解您的意思,但我认为这就是您想要的。有点...:)

struct JSONResponse: Decodable {

    struct AucListDoc: Decodable {
        // I renamed some properties to suit conventions
        let displayName: String
        let listId: Int
        let fkComId: Int
    }

    enum CodingKeys: String, CodingKey {
        // don't need any key mapping here since the differences
        // between the json's key names and the structs' properties'
        // names are handled via the 'JSONDecoder's 'keyDecodingStrategy'
        // (see the bottom of the answer)
        case serverTime
        case error

        case data
        case response

        case numFound
        case docs
    }

    // I only added the properties you seem to care about here
    let serverTime: String
    let error: Bool
    let numFound: Int
    let docs: [AucListDoc]

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        // you can immediately get 'serverTime' and 'error'
        // from the outermost container
        serverTime = try container.decode(String.self, forKey: .serverTime)
        error = try container.decode(Bool.self, forKey: .error)

        // since 'numFound' and 'docs' are contained in the nested
        // 'response' container which itself is contained in the nested
        // 'data' container you first have to get those nested containers
        let data = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .data)
        let response = try data.nestedContainer(keyedBy: CodingKeys.self, forKey: .response)

        // now you can get 'numFound' and 'docs' from the nested
        // 'response' container
        numFound = try response.decode(Int.self, forKey: .numFound)
        docs = try response.decode([AucListDoc].self, forKey: .docs)
    }

}

您可以像这样对jsonData进行解码(不要忘记JSONDecoder的{​​{1}}):

keyDecodingStrategy