Как написать Codable, если в массиве словаря отсутствует один ключ - PullRequest
1 голос
/ 06 мая 2019

При ответе сервера иногда не хватает ключа «теги».Как мы должны написать кодируемую структуру для этого ответа.

[
  {
    "product_id": 10
    "product_name": "Bulb"
    "tags": ["x", "y", "z"]
  },
  {
    "product_id": 11
    "product_name": "Wire"
  }
]

расшифровка, как это

do {

    // decoding...
    let product_model = try JSONDecoder().decode([ProductItem].self, from: data)

} catch let error {

    print("Product list error(decoder): \(error.localizedDescription)") 
}

// Структура продукта

struct ProductItem: Codable {

    // variables
    let product_id: String?
    let product_name: String?
    let tags: [String]?

    // alternative keys...
    private enum CodingKeys: String, CodingKey {

        case product_id
        case product_name
        case tags // what i have to do here
    }
}

Ответы [ 3 ]

2 голосов
/ 06 мая 2019

В вашем JSON отсутствуют некоторые запятые, правильный JSON:

[
    {
        "product_id": 10,
        "product_name": "Bulb",
        "tags": ["x", "y", "z"]
    },
    {
        "product_id": 11,
        "product_name": "Wire"
    }
]

product_id в вашем коде - это String, тогда как в вашем JSON это число.

Swift может фактически обрабатывать пропущенные ключи, как это, если вы сделаете свойство необязательным, что вы правильно сделали здесь.tags будет назначено nil, если в JSON нет ключа.Поэтому вам не нужно ничего делать, кроме как изменить product_id на Int.

Ваши имена свойств также можно переименовать, чтобы они стали более Swifty, если вы используете опцию convertFromSnakeCase при декодировании:

struct ProductItem: Codable {

    let productId: Int?
    let productName: String?
    let tags: [String]?
}

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decoded = try! decoder.decode([ProductItem].self, from: data)
print(decoded[1].tags) // nil
2 голосов
/ 06 мая 2019

Похоже, вы JSON не правильно.Она должна выглядеть примерно так:

[
  {
    "product_id": 10,
    "product_name": "Bulb",
    "tags": ["x", "y", "z"]
  },
  {
    "product_id": 11,
    "product_name": "Wire"
  }
]

, и для этого ваша структура должна быть похожа на:

struct ProductItem: Codable {

    // variables
    let product_id: Int
    let product_name: String
    let tags: [String]?
}

Вам не нужно указывать CodingKeys, если ваши переменныев структуре называются так же, как ключи в объекте JSON.Также помните, что "product_id": 10, - это число, поэтому вы должны использовать Int, а не String.

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

@ dahiya_boy спасибо.Этот код ниже работает нормально.

struct ProductItem : Codable {

        let productId : Int?
        let productName : String?
        let tags : [String]?

        enum CodingKeys: String, CodingKey {
                case productId = "product_id"
                case productName = "product_name"
                case tags = "tags"
        }

        init(from decoder: Decoder) throws {
                let values = try decoder.container(keyedBy: CodingKeys.self)
                productId = try values.decodeIfPresent(Int.self, forKey: .productId)
                productName = try values.decodeIfPresent(String.self, forKey: .productName)
                tags = try values.decodeIfPresent([String].self, forKey: .tags)
        }

}
...