gpt4 book ai didi

Swift 4 Decodable - 以枚举为键的字典

转载 作者:搜寻专家 更新时间:2023-11-01 05:32:23 32 4
gpt4 key购买 nike

我的数据结构有一个枚举作为键,我希望下面的内容能够自动解码。这是错误还是某些配置问题?

import Foundation

enum AnEnum: String, Codable {
case enumValue
}

struct AStruct: Codable {
let dictionary: [AnEnum: String]
}

let jsonDict = ["dictionary": ["enumValue": "someString"]]
let data = try! JSONSerialization.data(withJSONObject: jsonDict, options: .prettyPrinted)
let decoder = JSONDecoder()
do {
try decoder.decode(AStruct.self, from: data)
} catch {
print(error)
}

我得到的错误是这个,似乎将字典与数组混淆了。

typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [Optional(__lldb_expr_85.AStruct.(CodingKeys in _0E2FD0A9B523101D0DCD67578F72D1DD).dictionary)], debugDescription: "Expected to decode Array but found a dictionary instead."))

最佳答案

问题是 Dictionary 's Codable conformance目前只能妥善处理StringInt键。与任何其他字典 Key类型(KeyEncodable/Decodable ),它使用具有交替键值的 unkeyed 容器(JSON 数组)进行编码和解码。

因此在尝试解码 JSON 时:

{"dictionary": {"enumValue": "someString"}}

进入AStruct , "dictionary" 的值键应该是一个数组。

所以,

let jsonDict = ["dictionary": ["enumValue", "someString"]]

会工作,产生 JSON:

{"dictionary": ["enumValue", "someString"]}

然后将被解码为:

AStruct(dictionary: [AnEnum.enumValue: "someString"])

但是,我真的认为DictionaryCodable一致性应该能够正确处理任何CodingKey符合类型作为其 Key (AnEnum 可以)——因为它可以使用该 key 编码和解码到带 key 的容器中(请随时向 file a bug 提出要求)。

在实现之前(如果有的话),我们总是可以构建一个包装器类型来做到这一点:

struct CodableDictionary<Key : Hashable, Value : Codable> : Codable where Key : CodingKey {

let decoded: [Key: Value]

init(_ decoded: [Key: Value]) {
self.decoded = decoded
}

init(from decoder: Decoder) throws {

let container = try decoder.container(keyedBy: Key.self)

decoded = Dictionary(uniqueKeysWithValues:
try container.allKeys.lazy.map {
(key: $0, value: try container.decode(Value.self, forKey: $0))
}
)
}

func encode(to encoder: Encoder) throws {

var container = encoder.container(keyedBy: Key.self)

for (key, value) in decoded {
try container.encode(value, forKey: key)
}
}
}

然后像这样实现:

enum AnEnum : String, CodingKey {
case enumValue
}

struct AStruct: Codable {

let dictionary: [AnEnum: String]

private enum CodingKeys : CodingKey {
case dictionary
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
dictionary = try container.decode(CodableDictionary.self, forKey: .dictionary).decoded
}

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(CodableDictionary(dictionary), forKey: .dictionary)
}
}

(或者只拥有 dictionary 类型的 CodableDictionary<AnEnum, String> 属性并使用自动生成的 Codable 一致性——然后就用 dictionary.decoded 来说话)

现在我们可以按预期解码嵌套的 JSON 对象:

let data = """
{"dictionary": {"enumValue": "someString"}}
""".data(using: .utf8)!

let decoder = JSONDecoder()
do {
let result = try decoder.decode(AStruct.self, from: data)
print(result)
} catch {
print(error)
}

// AStruct(dictionary: [AnEnum.enumValue: "someString"])

虽然说了这么多,但可以说,您使用带有 enum 的字典所取得的一切因为 key 只是一个 struct具有可选属性(如果您希望给定值始终存在;使其成为非可选属性)。

因此您可能只希望您的模型看起来像:

struct BStruct : Codable {
var enumValue: String?
}

struct AStruct: Codable {

private enum CodingKeys : String, CodingKey {
case bStruct = "dictionary"
}

let bStruct: BStruct
}

这对您当前的 JSON 来说工作得很好:

let data = """
{"dictionary": {"enumValue": "someString"}}
""".data(using: .utf8)!

let decoder = JSONDecoder()
do {
let result = try decoder.decode(AStruct.self, from: data)
print(result)
} catch {
print(error)
}

// AStruct(bStruct: BStruct(enumValue: Optional("someString")))

关于Swift 4 Decodable - 以枚举为键的字典,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54784007/

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