Using Codable on a dynamic type/object

前端 未结 2 357
南方客
南方客 2020-12-03 05:54

Hi I have the following structure nested in a bigger structure that is returned from an api call but I can\'t manage to encode/decode this part. The problem I am having is t

相关标签:
2条回答
  • 2020-12-03 06:39

    Since you linked to my answer to another question, I will expand that one to answer yours.

    Truth is, all keys are known at runtime if you know where to look:

    struct GenericCodingKeys: CodingKey {
        var intValue: Int?
        var stringValue: String
    
        init?(intValue: Int) { self.intValue = intValue; self.stringValue = "\(intValue)" }
        init?(stringValue: String) { self.stringValue = stringValue }
    
        static func makeKey(name: String) -> GenericCodingKeys {
            return GenericCodingKeys(stringValue: name)!
        }
    }
    
    
    struct MyModel: Decodable {
        var current: String
        var hash: String
        var values: [String: String]
    
        private enum CodingKeys: String, CodingKey {
            case current
            case hash
            case values
        }
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            current = try container.decode(String.self, forKey: .current)
            hash = try container.decode(String.self, forKey: .hash)
    
            values = [String: String]()
            let subContainer = try container.nestedContainer(keyedBy: GenericCodingKeys.self, forKey: .values)
            for key in subContainer.allKeys {
                values[key.stringValue] = try subContainer.decode(String.self, forKey: key)
            }
        }
    }
    

    Usage:

    let jsonData = """
    {
        "current": "a value",
        "hash": "a value",
        "values": {
            "key1": "customValue",
            "key2": "customValue"
        }
    }
    """.data(using: .utf8)!
    
    let model = try JSONDecoder().decode(MyModel.self, from: jsonData)
    
    0 讨论(0)
  • 2020-12-03 06:47

    Simplified answer, it is working with dictionary [String: String] (instatead of String you can use other struct):

    let jsonData = """
    {
        "current": "a value",
        "hash": "a value",
        "values": {
            "key1": "customValue",
            "key2": "customValue"
        }
    }
    """.data(using: .utf8)!
    
    struct MyModel: Decodable {
        var current: String
        var hash: String
        var values: [String: String]
    }
    
    let model = try JSONDecoder().decode(MyModel.self, from: jsonData)
    
    for (key,value) in model.values {
        print("key: \(key) value: \(value)")
    }
    
    0 讨论(0)
提交回复
热议问题