简体   繁体   English

Swift Codable:无法解码 [String: Any] 或 [String: Decodable] 类型的字典

[英]Swift Codable: Cannot decode dictionary of type [String: Any] or [String: Decodable]

In my custom initializer I'd like to decode a dictionary from JSON and then assign its values to properties in the class. To my surprise, compiler does not allow me to decode the dictionary, I get the error:在我的自定义初始化程序中,我想解码 JSON 中的字典,然后将其值分配给 class 中的属性。令我惊讶的是,编译器不允许我解码字典,我收到错误消息:

Value of protocol type 'Any' cannot conform to 'Decodable'; only struct/enum/class types can conform to protocols

If I try to decode dictionary of type [String: Decodable] the error message says:如果我尝试解码 [String: Decodable] 类型的字典,则错误消息显示:

Value of protocol type 'Decodable' cannot conform to 'Decodable'; only struct/enum/class types can conform to protocols

My initializer looks like this:我的初始化器看起来像这样:

public let total: Int

required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    ...
    if let dict = try container.decodeIfPresent([String: Any].self, forKey: .tracks),
           let value = dict["total"] as? Int { // Error is displayed at this line
        total = value
    } else {
        total = 0
    }
    ...
}

When I looked for the answer I found this answer and according to it the code above should not cause any problems.当我寻找答案时,我找到了这个答案,根据它,上面的代码应该不会引起任何问题。

What you are looking for is nestedContainer .您正在寻找的是nestedContainer It helps you "skip" a hierarchy level in your JSON. Ie: let's imagine that in your code, it's all in the same level (one struct), but in the JSON, it's not, there is a sub dictionary.它可以帮助您“跳过”JSON 中的层次结构级别。即:假设在您的代码中,它们都在同一级别(一个结构)中,但在 JSON 中,它不是,有一个子字典。

For test purpose, your JSON might look like:出于测试目的,您的 JSON 可能如下所示:

{
    "title": "normal",
    "tracks": {
                   "name": "myName",
                   "total": 3
              }
}

If we want in our model:如果我们想要在我们的 model 中:

struct TestStruct: Codable {
    let title: String
    let name: String
    let total: Int
}

We need to use nestedContainer(keyedBy: forKey:) :我们需要使用nestedContainer(keyedBy: forKey:)

extension TestStruct {
    enum TopLevelKeys: String, CodingKey {
        case title
        case tracks
    }
    
    enum NestedLevelCodingKeys: String, CodingKey {
        case name
        case total
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: TopLevelKeys.self)
        self.title = try container.decode(String.self, forKey: .title)
        let subcontainer = try container.nestedContainer(keyedBy: NestedLevelCodingKeys.self, forKey: TopLevelKeys.tracks)
        self.name = try subcontainer.decode(String.self, forKey: .name)
        self.total = try subcontainer.decode(Int.self, forKey: .total) //You can use here a `decodeIfPresent()` if needed, use default values, etc.

    }
}

In your sample, you used decodeIfPresent() for the subdictionary.在您的示例中,您使用decodeIfPresent()作为子词典。 It's unclear if it was for test purpose, or if the sub dictionary was sometimes not present.目前还不清楚它是出于测试目的,还是子词典有时不存在。 If that's the case and you can have a JSON like this:如果是这种情况,您可以像这样拥有 JSON:

{
    "title": "normal"
} 

Then, before calling nestedContainer(keyedBy: forKey:) , use if container.contains(TopLevelKeys.tracks) {} and set default values if needed in the else case.然后,在调用nestedContainer(keyedBy: forKey:)之前,使用if container.contains(TopLevelKeys.tracks) {}并在else情况下根据需要设置默认值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 编码错误-预期对字典进行解码 <String, Any> 但发现数组 - Codable Error - Expected to decode Dictionary <String, Any> but found array Swift 4 Codable 从字符串解码 URL - Swift 4 Codable decode URL from String Swift 使用可解码协议解码字符串中的字典数组 - Swift Decode Array of Dictionaries inside String using Decodable Protocol 如果字符串中的一个值包含(“),则Swift Codable无法解码 - Swift Codable not able to decode if string contains (") in one of the values 致命错误:字典 <String, Any> 不符合Decodable,因为Any不符合Decodable - Fatal error: Dictionary<String, Any> does not conform to Decodable because Any does not conform to Decodable 如何在没有密钥的 Swift 5 可解码协议中解码字典数组类型的属性? - How to decode a property with type of Array of dictionary in Swift 5 decodable protocol without key? 带字典的Swift 4 Codable数组具有String和Array的值 - Swift 4 Codable array with dictionary has value of String and Array 类型不匹配(Swift.Dictionary<Swift.String, Any> debugDescription: &quot;预期解码字典<String, Any>而是找到了一个数组。” - typeMismatch(Swift.Dictionary<Swift.String, Any> debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead." 在可解码解码函数中检索 JSON 字符串 - Retrieving JSON String in Decodable decode function 无法用 Swift 解码 - Unable to decode with Swift decodable
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM