keyNotFound в codableKey для ответа json - PullRequest
0 голосов
/ 06 мая 2020

Json синтаксический анализ ответа в кодируемую строку для обнаружения ошибки KeyNotFound. KeyNotFound при кодировании в класс оболочки

    Unexpected error: keyNotFound(CodingKeys(stringValue: "id", intValue: nil), 
Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil)], 
debugDescription: "No value associated with key CodingKeys(stringValue: \"id\", intValue: nil)
 (\"id\").", underlyingError: nil)).

Данные ответа

{
    "msg": {
        "success": [
            ""
        ]
    },
    "data": {
        "jobs": {
            "current_page": 1,
            "data": [
                {
                    "id": 154,
                    "user": "UserName"}
]
}
}
}

Сервисный вызов

let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
    if let error = error {
        print("error: \(error)")
    } else {
        if let response = response as? HTTPURLResponse {
            print("statusCode: \(response.statusCode)")
        }
        if let data = data, let dataString = String(data: data, encoding: .utf8) {
            let jsonData = dataString.data(using: .utf8)!

            do {
                let jsonDecoder = JSONDecoder()
                let user = try jsonDecoder.decode(JobListModel.self, from: data)
                print("Hello \(user.msg )")
            } catch {
                print("Unexpected error: \(error).")
            }
        }
    }
}

ModelClass.

struct JobListModel: Codable {

    let msg: Msg
    let data: Data

    private enum CodingKeys: String, CodingKey {
        case msg = "msg"
        case data = "data"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        msg = try values.decode(Msg.self, forKey: .msg)
        data = try values.decode(Data.self, forKey: .data)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(msg, forKey: .msg)
        try container.encode(data, forKey: .data)
    }

}

Ответы [ 2 ]

0 голосов
/ 06 мая 2020

Причина:

В вашей модели вы используете Data как тип ключа data в ответе JSON.

Data - это предопределенный тип, и поэтому при синтаксическом анализе возникает ошибка.

Решение:

Вам необходимо изменить его на какой-то настраиваемый тип Например. JobListData. Итак, ваши модели Codable должны выглядеть так:

struct JobListModel: Codable {
    let msg: Msg
    let data: JobListData
}

struct JobListData: Codable {
    let jobs: Jobs
}

struct Jobs: Codable {
    let currentPage: Int
    let data: [JobsData]
}

struct JobsData: Codable {
    let id: Int
    let user: String
}

struct Msg: Codable {
    let success: [String]
}

Теперь вы можете разобрать data вот так,

do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let response = try decoder.decode(JobListModel.self, from: data)
    print(response)
} catch {
    print(error)
}

в приведенном выше коде Я использовал convertFromSnakeCase как decoder's keyDecodingStrategy. Благодаря этому вы можете избежать явного определения enum CodingKeys только для обработки ключей змеиного регистра в ответе json.

Примечание: Не пишите определения init(from:) и encode(to:) явно, когда нет ничего конкретного c для анализа. Прямой синтаксический анализ в Codable будет выполняться компилятором автоматически, если вы правильно спроектировали модель.

0 голосов
/ 06 мая 2020

Это происходит из-за неправильной модели декодирования. Используйте модель ниже:

struct JobListModel: Codable {
    let msg: Msg
    let data: JobListData
}

struct JobListData: Codable {
    let jobs: Jobs
}

struct Jobs: Codable {
    let currentPage: Int
    let data: [JobData]

    enum CodingKeys: String, CodingKey {
        case currentPage = "current_page"
        case data
    }
}

struct JobData: Codable {
    let id: Int
    let user: String
}

struct Msg: Codable {
    let success: [String]
}
...