假设我有一个变量
clients: [String: Client]
。 Client 是我的父类,我有一个子类SpecialClient
。这两个类都是可编码的,我想将 JSON 字符串解码到字典中。在这本词典中,我希望同时拥有两种类型的客户。
为此,JSON 字符串中的每个客户端都有一个变量
clientType
,它定义它是否是 SpecialClient
。我现在需要读取这个值,并根据它在字典中添加 SpecialClient
或普通 Client
。
目前,我只有这样的东西,显然只是在字典中生成 Clients 。我做了一些研究,但找不到方法。
class Object: Codable {
var clients: [String:Client]
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.clients = try container.decode([String : Client].self, forKey: .clients)
}
}
拥有一个包含来自 Client 和 SpecialClient 类的客户端的容器。
更多上下文:JSON 内容看起来像这样:
["clients": {
"clientId1111" = {
clientType = BASIC_TYPE;
label = "Test";
...
};]
由于有关 JSON 结构的问题缺乏清晰度,因此在此答案中做出了一个假设。我假设结构是:
{
"clients": [
{
"clientId1111": {
"clientType": "BASIC_TYPE",
"label": "Test1"
}
},
//...
{
"clientId1114": {
"clientType": "SPECIAL_TYPE",
"label": "Test4",
"specialCode": 4
}
}
]
}
即一个数组字典,在顶层由
clients
键控,如果不是这种情况,您可能需要调整答案。
在此基础上我创建了一些模型:
基本
Client
模型。这符合开箱即用的可解码,因此不需要自定义解码。
class Client: Decodable {
let label: String
let clientType: String
init(label: String, clientType: String) {
self.label = label
self.clientType = clientType
}
}
SpecialClient
型号:
class SpecialClient: Client {
let specialCode: Int //just to differentiate from Client
enum CodingKeys: CodingKey {
case label, clientType, specialCode
}
required init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
specialCode = try container.decode(Int.self, forKey: .specialCode)
let label = try container.decode(String.self, forKey: .label)
let type = try container.decode(String.self, forKey: .clientType)
super.init(label: label, clientType: type)
}
}
使用自定义解码器并使用数据字段调用
super.init
。 [我觉得有更好的方法来处理这个问题,但自从我使用 coddle 继承以来已经很久了......!]
然后大部分解码发生在
Object
模型中
class Object: Decodable {
var clients: [String:Client]
enum CodingKeys: CodingKey {
case clients
}
required init(from decoder: any Decoder) throws {
var imports = [ [String: Client] ]()
do {
let container = try decoder.container(keyedBy: CodingKeys.self)
var dataContainer = try container.nestedUnkeyedContainer(forKey: .clients)
while !dataContainer.isAtEnd {
do {
let imported = try dataContainer.decode([String: SpecialClient].self)
imports.append(imported)
} catch {
let imported = try dataContainer.decode([String: Client].self)
imports.append(imported)
}
}
} catch {
fatalError(error.localizedDescription)
}
clients = imports.reduce(into:[String: Client]()){ master, childDict in
childDict.forEach{ childPair in
master[childPair.key] = childPair.value
}
}
}
}
这里它使用嵌套的无键容器,因此您可以访问字典键(
clientId###
)及其值(Client
或SpecialClient
)。[String: Client/SpecialClient]
字典,被附加到临时数组中。
最后,它将临时字典数组减少(扁平化)到主
clients
字典中。