Тип Swift не соответствует «декодируемому»

Я пытаюсь написать класс 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
        }
]
Конечные и Readonly классы в PHP
Конечные и Readonly классы в PHP
В прошлом, когда вы не хотели, чтобы другие классы расширяли определенный класс, вы могли пометить его как final.
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
Если вы уже умеете работать с React, создание мобильных приложений для iOS и Android - это новое приключение, в котором вы сможете применить свои...
БЭМ: Конвенция об именовании CSS
БЭМ: Конвенция об именовании CSS
Я часто вижу беспорядочный код CSS, особенно если проект большой. Кроме того, я совершал эту ошибку в профессиональных или личных проектах и...
Революционная веб-разработка ServiceNow
Революционная веб-разработка ServiceNow
В быстро развивающемся мире веб-разработки ServiceNow для достижения успеха крайне важно оставаться на вершине последних тенденций и технологий. По...
Как добавить SEO(Search Engine Optimization) в наше веб-приложение и как это работает?
Как добавить SEO(Search Engine Optimization) в наше веб-приложение и как это работает?
Заголовок веб-страницы играет наиболее важную роль в SEO, он помогает поисковой системе понять, о чем ваш сайт.
Конфигурация Jest в angular
Конфигурация Jest в angular
В этой статье я рассказываю обо всех необходимых шагах, которые нужно выполнить при настройке jest в angular.
0
0
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Попробуйте этот подход,

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

Это решило мою проблему, однако мне любопытно, почему сообщение об ошибке исходит от Decodable, а не указывает на то, что виновником является Hashable. Любые идеи здесь?

Anon 15.02.2023 05:16

Обновил мой ответ другой опечаткой, используйте wishlist не wishlists в своем Settings , он должен точно соответствовать данным json. Обратите внимание, что вам также не хватает последнего } в ваших данных json.

workingdog support Ukraine 15.02.2023 05:19

@ Анон, я пытался объяснить это в своем ответе. И спасибо @workingdogsupportUkraine! Это хорошее место! Я не понимаю.

Sweeper 15.02.2023 05:23

Ваша первая попытка не работает, потому что вы указали только подмножество ключей, которые хотите декодировать, в перечислении 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

Другие вопросы по теме