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 that the customKey and customValue are both dynamic.
{
"current" : "a value"
"hash" : "some value"
"values": {
"customkey": "customValue",
"customKey": "customValue"
}
}
I tried something like var values: [String:String]
But that is obviously not working because its not actually an array of [String:String]
.
Codable allows you to insert an additional clarifying stage into the process of decoding data into a Swift object. This stage is the “parsed object,” whose properties and keys match up directly to the data, but whose types have been decoded into Swift objects.
Remember, Swift's String , Int , and Bool are all Codable ! Earlier I wrote that your structs, enums, and classes can conform to Codable . Swift can generate the code needed to extract data to populate a struct's properties from JSON data as long as all properties conform to Codable .
Introduced in Swift 4, the Codable API enables us to leverage the compiler in order to generate much of the code needed to encode and decode data to/from a serialized format, like JSON. Codable is actually a type alias that combines two protocols — Encodable and Decodable — into one.
Codable is a type alias for the Encodable and Decodable protocols. When you use Codable as a type or a generic constraint, it matches any type that conforms to both protocols.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With