Swift Json 如何在没有顶级密钥和自动生成的密钥的情况下解码

问题描述

这个对我没有帮助:Swift 4 parsing json numeric keys with 1+n amount

情况不同。

我有这个 JSON(简化了一点):

{
        "1": {
            "name": "Tea room","description": "A room for tea"
        },"2": {
            "name": "Playground","description": "Here you can play all day long"
        },"3": {
            "name": "Kitchen","description": "Hungry persons can go here"
        }
    }

我的问题是如何解码。我正在使用 Swift 版本 5。我正在尝试使用 JSONDecoder().decode();

键“1”、“2”和“3”实际上是 ID,由 API 生成。我不知道我会收到多少房间。我不知道他们将拥有什么密钥,但我需要知道密钥(Id)才能走得更远。

我正在做这样的事情:

struct Rooms: Decodable {
  let id: Int; //THIS ONE IS MY PROBLEM
  let rooms: [Room]?;
}

struct Room: Decodable {
    let name: String?;
    let description: String?;
        
    private enum CodingKeys: String,CodingKey {
        case name,description;
    }
}

//Here trying to decode the JSON I got back.
JSONDecoder().decode([Group].self,from: jsonResult);

这让我头疼:)

谁能帮我找到正确的方向?

解决方法

您可以将其解码为字典:[String: Room]

JSONDecoder().decode([String: Room].self,from: jsonResult);
,

鉴于此模型(如果属性名称与您的 JSON 键名称相同,则不需要 CodingKeys):

struct Room: Decodable {
    let name: String?
    let description: String?
}

您可以将此 JSON 解码为 [String: Room] 类型:

let decoder = JSONDecoder()

do {
    let decoded = try decoder.decode([String: Room].self,from: jsonResult)
    print(decoded)
} catch {
    print(error)
}
,

因为你需要有 id,所以它应该是 Room 的一个属性

struct Room: Decodable {
    var id: Int?
    let name: String
    let description: String
}

这样我们就可以将json解码为[String: Room]的字典,并使用map为每个房间分配正确的id

do {
    let dictionary = try JSONDecoder().decode([String: Room].self,from: data)
    let rooms = dictionary.map { tuple -> Room in
        var room = tuple.value
        room.id = Int(tuple.key)
        return room
    }
    print(rooms)
} catch {
    print(error)
}

如果您不想使 id 可选,您可以将其解码为字典字典并在映射时创建 Room 对象

do {
    let dictionary = try JSONDecoder().decode([String: [String: String]].self,from: data)
    let rooms = dictionary.compactMap { tuple -> Room? in
        guard let id = Int(tuple.key),let name = tuple.value["name"],let description = tuple.value["description"] else {
            return nil
        }
        return Room(id: id,name: name,description: description)
    }
    print(rooms)
} catch {
    print(error)
}