Я пытаюсь написать класс UserModel, чтобы помочь с расшифровкой ответа JSON, и сталкиваюсь со следующей ошибкой:
Type 'UserModel' does not conform to protocol 'Decodable'
Моя структура UserModel выглядит следующим образом.
struct UserModel: Codable, Hashable, Identifiable {
let id: String
let email: String
let tokenIssuedAt: Int
let createdAt: String
let updatedAt: String
let settings: Settings
enum CodingKeys: String, CodingKey {
case tokenIssuedAt = "token_issued_at"
case createdAt = "created_at"
case updatedAt = "updated_at"
}
struct Settings: Codable {
var wishlists, collection, findable: Bool
}
}
Если я удалю переменную настроек из этой структуры, а также структуру настроек, эта ошибка исчезнет, но, учитывая, что настройки можно кодировать, я не понимаю, почему это вызывает поломку моей структуры UserModel.
Я попытался обновить ключи кодирования следующим образом:
enum CodingKeys: String, CodingKey {
case id
case email
case tokenIssuedAt = "token_issued_at"
case createdAt = "created_at"
case updatedAt = "updated_at"
case settings
}
А также добавление инициализирующего декодера, такого как:
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
settings = try container.decode(Settings.self, forKey: .settings)
}
Однако затем я получаю следующее сообщение об ошибке:
Тип «UserModel» не соответствует протоколу «Equatable» Тип «UserModel» не соответствует протоколу «Hashable»
Это происходит из-за ошибки, которую я сделал в ключах кодирования, в структуре настроек или из-за чего-то еще, что я мог упустить из виду при заглушке этой структуры?
JSON, который я пытаюсь декодировать, выглядит следующим образом:
[
{
"id": "1cc02c5f-2cb3-4546-a2d7-a824188e667d",
"email": "trenton@example.com",
"token_issued_at": 1676418140,
"created_at": "2023-02-09T01:51:08.733Z",
"updated_at": "2023-02-14T23:46:14.136Z",
"settings": {
"collection": false,
"wishlist": false,
"findable": true
}
]
Попробуйте этот подход,
struct UserModel: Codable, Identifiable { // <-- here
let id: String
let email: String
let tokenIssuedAt: Int
let createdAt: String
let updatedAt: String
let settings: Settings
enum CodingKeys: String, CodingKey {
case tokenIssuedAt = "token_issued_at"
case createdAt = "created_at"
case updatedAt = "updated_at"
case id, email, settings // <-- here
}
struct Settings: Codable {
var wishlist, collection, findable: Bool // <-- here wishlist, not s
}
}
Обратите внимание, если вам действительно нужен Hashable в UserModel, поставьте его также в Settings
Обновил мой ответ другой опечаткой, используйте wishlist не wishlists в своем Settings , он должен точно соответствовать данным json. Обратите внимание, что вам также не хватает последнего } в ваших данных json.
@ Анон, я пытался объяснить это в своем ответе. И спасибо @workingdogsupportUkraine! Это хорошее место! Я не понимаю.
Ваша первая попытка не работает, потому что вы указали только подмножество ключей, которые хотите декодировать, в перечислении CodingKeys. Для компилятора это означает, что вы хотите декодировать только эти ключи в JSON. Однако, если декодированы только эти ключи, то id, email и settings не будут инициализированы ничем при декодировании, что противоречит правилам Swift.
Когда вы добавили все ключи в CodingKeys, по-прежнему возникает ошибка, говорящая, что UserModel не соответствует Hashable и Equatable. Это потому, что Settings не соответствует ни одному из них. Чтобы автоматически создать соответствие для Hashable, все участники должны быть Hashable.
Либо заставить Settings соответствовать Hashable
struct Settings: Hashable, Codable {
var wishlist, collection, findable: Bool
}
Или заставить UserModel не соответствовать Hashable,
struct UserModel: Codable, Identifiable {
Исправит ошибку.
Вы должны удалить init(from:), который вы добавили, так как он декодирует только settings. Вы можете просто использовать тот, который Swift генерирует автоматически.
Фактически, вы также можете удалить перечисление ключей кодирования в UserModel. Сопоставление ключей кодирования из змеиного футляра можно выполнить с помощью параметра convertFromSnakeCase в декодере. Вы можете просто установить это в декодере при декодировании:
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
Это решило мою проблему, однако мне любопытно, почему сообщение об ошибке исходит от Decodable, а не указывает на то, что виновником является Hashable. Любые идеи здесь?