Расшифровка данных с помощью 'Codable'

Я пытаюсь декодировать массив объектов моей модели (Каталог) из JSON, который выглядит так после сериализации соответствующего объекта «Данные».

 { "id" : 5,
   "catalogs" : [ {catalogKeyValue1},{catalogKeyValue2}]
 }

Мой объект модели выглядит так

struct Catalog : Codable{
 var id : Int
 var name : String
 var categoryId : Int
 var minProductPrice : Int
 var maxProductDiscount : Int?
 var shareText : String
 var collageImage : String
 var collageImageAspectRatio : Double?
 var shipping : [String : Int]?
 var description : String
}

Мне нужно получить массив каталогов (который вложен в ключ 'catalogs' в JSON) после декодирования. Я полностью понимаю, как использовать вложенные контейнеры и писать собственный инициализатор для структуры каталога. Как я могу добиться этого без необходимости писать другую структуру Codable для внешний JSOn, который выглядит так

struct CatalogArray: Codable {
 var catalogs : [Catalog]
}

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

let catalogArray = try decoder.decode(CatalogArray.self, from: validData)

Моя проблема в том, что мне не нужна эта структура catalogArray. Есть ли способ декодирования объектов модели Каталога без создания ненужных вложенных структур.


person Tarun Bhargava    schedule 08.02.2019    source источник
comment
Возможный дубликат Как декодировать вложенную структуру JSON с протоколом Swift Decodable?   -  person Prashant Tukadiya    schedule 08.02.2019
comment
Вам необходимо написать дополнительный код, теоретически это должно быть возможно достичь без промежуточных структур, однако это потребует написания большего количества кода декодирования. Так что вам все равно придется писать дополнительный код, с промежуточной структурой или без нее.   -  person Cristik    schedule 08.02.2019
comment
Что не так с большим количеством структур? Если вы дадите им хорошие имена, они не будут загромождать ваш код.   -  person Sweeper    schedule 08.02.2019
comment
Проблема с большим количеством Codable структур заключается в том, что мне нужно будет создать другую структуру, если тот же массив каталогов идет с другим ключом в другом ответе API.   -  person Tarun Bhargava    schedule 08.02.2019
comment
@TarunBhargava Вы можете создать общую структуру, как мой ответ   -  person Prashant Tukadiya    schedule 08.02.2019
comment
@Cristik Я говорю о двух ответах API. Один дает мне [Каталог] с ключевыми «каталогами», а другой, скажем, с ключом «new_catalogs». Как бы мне не создать новую структуру для второго случая и при этом получить свой массив [Каталог] для обоих случаев?   -  person Tarun Bhargava    schedule 08.02.2019
comment
@Cristik Я не понимаю. Не могли бы вы сказать мне, как я могу получить массив каталога, подобный этому, из ответа сырых данных обоих API без необходимости изменять ключ (catalogs, здесь, в struct CatalogArray, и, скажем, newCatalogs во втором ответе), против которого я получу [Catalog] в JSON? let catalogArray = try decoder.decode(CatalogArray.self, from: validData)   -  person Tarun Bhargava    schedule 08.02.2019


Ответы (2)


Вы можете делать это вместо того, чтобы каждый раз создавать новую структуру: try container.decode([Catalog].self, forKey: "Catalogs")

Массивы типа Codable автоматически кодируются.

person Atharva Vaidya    schedule 08.02.2019
comment
Это не сработает, потому что единственный способ получить контейнер будет в методе init (from decoder: Decoder) одной модели каталога. И после выполнения попытки container.decode ([Catalog] .self, forKey: Catalogs) я получу массив каталогов в инициализаторе одного объекта модели каталога. - person Tarun Bhargava; 08.02.2019

Согласно вашему комментарию

Проблема с большим количеством кодируемых структур заключается в том, что мне нужно будет создать другую структуру, если тот же массив каталогов поставляется с другим ключом в другом ответе API.

Вы можете создать общую структуру, которая сделает то же самое за вас. вот пример

struct GeneralResponse<T:Codable>: Codable {
    let code: Int
    let catalogs: T?

    enum CodingKeys: String, CodingKey {
        case code = "id"
        case catalogs = "catalogs"
    }

    public init(from decoder:Decoder) throws {
        let contaienr = try  decoder.container(keyedBy: CodingKeys.self)
        code = try contaienr.decode(Int.self, forKey: .code)


        do {
            let object = try contaienr.decodeIfPresent(T.self, forKey: .data)
            catalogs = object

        } catch {
            catalogs = nil
        }

    }

}

В настоящее время

Вы можете использовать это с различными типами каталогов структур

как

GeneralResponse<[Catalogs]> or GeneralResponse<[CatalogsAnother]>

Надеюсь, это будет полезно

person Prashant Tukadiya    schedule 08.02.2019
comment
Это не решит мою проблему, поскольку это не сработает, если другой GeneralResponse (ответ API) имеет [Catalog] array против ключа, отличного от ключа "catalogs". Это приведет к той же проблеме создания другой структуры с этим другим ключом. ` - person Tarun Bhargava; 08.02.2019