gpt4 book ai didi

ios - 使用 Codable 解析嵌套的非键控 JSON

转载 作者:行者123 更新时间:2023-11-28 23:24:55 26 4
gpt4 key购买 nike

我正在尝试使用 Codable 解析一组异构对象。这些对象也未加密。我应该注意到我的容器结构是正确的,因为它确实在所有正确的时间循环并打印“它是 type1”,如下所示。我只是不知道如何访问实际对象。这是我的代码:

var data: [Any]

public init(from decoder: Decoder) throws {
var container = try! decoder.container(keyedBy: CodingKeys.self).nestedUnkeyedContainer(forKey: .data)

while !container.isAtEnd {
var itemContainer = try container.nestedContainer(keyedBy: CodingKeys.self)

let itemType = try itemContainer.decode(String.self, forKey: .type)
switch itemType {
case "type1":
print("it is type1")
// this does not compile, but is what I need
//let objectOfItem1 = try itemContainer.decode(Type1.self)

// this compiles, but doesn't work because there is no key with these objects
//let objectOfItem1 = try itemContainer.decode(Type1, forKey: .type)
default:
print("test:: it is the default")
}
}
}

private enum CodingKeys: String, CodingKey {
case data
case type
}

这里是我尝试解码的 JSON(为了清楚起见,提交了许多属性):

"contents" : {
"data" : [
{
"type" : "type1",
"id" : "6a406cdd7a9cace5"
},
{
"type" : "type2",
"id" : "ljhdgsouilghoipsu"
}
]
}

我怎样才能正确地从这个结构中取出我的个人 Type1 对象?

最佳答案

我认为解决异构数据的简单方法是使用枚举作为临时类型来包装各种 Item 类型(都需要可编码):

为了让我自己进行测试,我稍微更改了您的 json 以便为我提供更多异构数据进行测试。我用过:

let json = """
{
"contents": {
"data": [
{
"type": "type1",
"id": "6a406cdd7a9cace5"
},
{
"type": "type2",
"dbl": 1.01
},
{
"type": "type3",
"int": 5
}
]
}
}

然后创建了这个json代表的三个final类型

struct Item1: Codable {
let type: String
let id: String
}
struct Item2: Codable {
let type: String
let dbl: Double
}
struct Item3: Codable {
let type: String
let int: Int
}

为了允许以类型安全的方式解码多种类型(按照Codable的要求),您需要使用可以表示(或包装)可能选项的单一类型。具有关联值的枚举对此非常有效

enum Interim {
case type1 (Item1)
case type2 (Item2)
case type3 (Item3)
case unknown //to handle unexpected json structures
}

到目前为止,还不错,但是当涉及到从 JSON 创建 Interim 时,它会变得稍微复杂一些。它将需要一个 CodingKey 枚举来表示所有 Item# 类型的所有可能的键,然后需要解码将所有这些键链接到其各自类型的 JSON和数据:

extension Interim: Decodable {
private enum InterimKeys: String, CodingKey {
case type
case id
case dbl
case int
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: InterimKeys.self)
let type = try container.decode(String.self, forKey: .type)
switch type {
case "type1":
let id = try container.decode(String.self, forKey: .id)
let item = Item1(type: type, id: id)
self = .type1(item)
case "type2":
let dbl = try container.decode(Double.self, forKey: .dbl)
let item = Item2(type: type, dbl: dbl)
self = .type2(item)
case "type3":
let int = try container.decode(Int.self, forKey: .int)
let item = Item3(type: type, int: int)
self = .type3(item)
default: self = .unknown
}
}
}

这提供了解码异构组件的机制,现在我们只需要处理更高级别的 key 。因为我们有一个 Decodable Interim 类型,所以这很简单:

struct DataArray: Decodable {
var data: [Interim]
}

struct Contents: Decodable {
var contents: DataArray
}

这意味着 json 可以像这样解码...

let data = Data(json.utf8)
let decoder = JSONDecoder()
do {
let contents = try decoder.decode(Contents.self, from: data)
print(contents)
} catch {
print("Failed to decode JSON")
print(error.localizedDescription)
}

这成功地将数据解码为嵌套结构,其中主要组件是 Interim 类型及其关联的 Item# 对象的数组。以上产生以下输出,显示这些嵌套类型:

Contents(contents: testbed.DataArray(data: [testbed.Interim.type1(testbed.Item1(type: "type1", id: "6a406cdd7a9cace5")), testbed.Interim.type2(testbed.Item2(type: "type2", dbl: 1.01)), testbed.Interim.type3(testbed.Item3(type: "type3", int: 5))]))

我认为应该有一种更安全的方法来使用类型删除来实现此目的,以提供更具可扩展性的解决方案,但我还没有完全理解这一点。

关于ios - 使用 Codable 解析嵌套的非键控 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58977019/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com