在 Swift 4 中将字典解码为数组

vik*_*lla 1 firebase firebase-realtime-database swift4 codable

我的数据结构如下所示。“人类”是一个键的字典,其值是人类的字典:

  "humans" : {
    "abc123" : {
      "name" : "Vince",
      "pets" : [ {
        "animal" : "dog",
        "name" : "Clifford"
      }, {
        "animal" : "fish",
        "name" : "Nemo"
      } ]
    },
    "xyz789" : {
      "name" : "Jack"
    }
  }
Run Code Online (Sandbox Code Playgroud)

所以我的 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
}
Run Code Online (Sandbox Code Playgroud)

我尝试像这样解码(使用CodableFirebase库):

let human = try FirebaseDecoder().decode([Human].self, from: value)
Run Code Online (Sandbox Code Playgroud)

但是当我尝试对具有某些对象数组的对象进行编码时,出现以下错误:

typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "不是数组",underlyingError: nil))

如何将字典的值正确编码为自定义 Swift 对象的数组?

vad*_*ian 5

有几个问题:

首先,你犯了一个常见的错误:你忽略了 JSON 的根对象,它是一个只有一个 key 的字典humans。这就是试图告诉你的错误。

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

let human = try FirebaseDecoder().decode(Root.self, from: value)
Run Code Online (Sandbox Code Playgroud)

但即使添加根结构也不起作用,因为 key 的值humans是字典,请注意{}

struct Root : Codable {
    let humans : [String:Human]
}
Run Code Online (Sandbox Code Playgroud)

最后,永远,永远,永远不要将可解码的结构成员声明为隐式未包装的可选值,它们要么是非可选的(是的,代码编译时没有感叹号),要么是常规可选的(?)

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
}
Run Code Online (Sandbox Code Playgroud)

如果您想要结构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)
    }
}
Run Code Online (Sandbox Code Playgroud)