Расшифровка словаря в виде массива в Swift 4 - PullRequest
0 голосов
/ 31 августа 2018

Моя структура данных выглядит следующим образом. «люди» - это словарь ключей, значения которых являются словарем человека:

  "humans" : {
    "abc123" : {
      "name" : "Vince",
      "pets" : [ {
        "animal" : "dog",
        "name" : "Clifford"
      }, {
        "animal" : "fish",
        "name" : "Nemo"
      } ]
    },
    "xyz789" : {
      "name" : "Jack"
    }
  }

И поэтому мои структуры Swift выглядят так, чтобы соответствовать:

struct Human: Codable {
    var name: String!
    var pets: [Pet]?
}

struct Pet: Codable {
    var name: String!
    var animal: Animal!
}

enum Animal: String, Codable {
    case cat
    case dog
    case fish
}

Я пытаюсь декодировать вот так (используя библиотеку CodableFirebase ):

let human = try FirebaseDecoder().decode([Human].self, from: value)

Но я получаю следующую ошибку при попытке кодировать объекты, у которых есть массивы какого-либо объекта:

typeMismatch (Swift.Array, Swift.DecodingError.Context (codingPath: [], debugDescription: «Не массив», underError: nil))

Как правильно кодировать значения словаря в виде массива моих пользовательских объектов Swift?

1 Ответ

0 голосов
/ 31 августа 2018

Есть несколько вопросов:

Прежде всего вы совершаете распространенную ошибку: вы игнорируете корневой объект JSON, представляющий собой словарь с одним ключом humans. Это ошибка, которая пытается вам сказать.

struct Root : Codable {
    let humans : [Human]
}

let human = try FirebaseDecoder().decode(Root.self, from: value)

Но даже добавление корневой структуры не работает, поскольку значение для ключа humans является словарем, обратите внимание на {}

struct Root : Codable {
    let humans : [String:Human]
}

Наконец, никогда, никогда, никогда объявляйте декодируемые элементы структуры как неявные развернутые необязательные опции, либо они не являются необязательными (да, код компилируется без восклицательных знаков), либо обычными необязательными (?)

struct Human: Codable {
    var name: String
    var pets: [Pet]?
}

struct Pet: Codable {
    var name: String
    var animal: Animal
}

enum Animal: String, Codable {
    case cat, dog, fish
}

Если вам нужен массив Human в структуре Root, а не словарь, вы должны написать собственный инициализатор

struct Root : Codable{
    let humans : [Human]

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let humanData = try container.decode([String:Human].self, forKey: .humans)
        humans = Array(humanData.values)
    }
}
...