I'm trying to decode my data into structs. Here is an example of one of my data structure as JSON:
{
"name": "abc",
"owner": "bcd",
"fallbackLanguage": "tr",
"localizedValues": {
"en": {
"description": "Lorem Ipsum Dolor Sit Amet"
},
"de": {
"description": "Sed Do Eiusmod Tempor Incididunt"
},
"tr": {
"description": "Consectetur Adipisicing Elit"
}
}
}
And struct for this JSON object is:
struct X {
let name: String
let owner: String
let fallbackLanguage: String
let description: String
}
Decoding name
, owner
and fallbackLanguage
is not a problem and already done. Here is the current CodingKey
and init(from:)
struct CodingKeys: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
self.intValue = intValue
self.stringValue = "\(intValue)"
}
static func makeKey(name: String) -> CodingKeys {
return CodingKeys.init(stringValue: name)!
}
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
owner = try container.decode(String.self, forKey: CodingKeys.makeKey(name: "owner"))
name = try container.decode(String.self, forKey: CodingKeys.makeKey(name: "name"))
fallbackLanguage = try container.decode(String.self, forKey: CodingKeys.makeKey(name: "fallbackLanguage"))
// FIXME: decode localizedValues into `description`
}
The problem is decoding description
, since it's hold in a multi-level dictionary, and it's value will change due to device locale.
In this example, if device locale is not en
, de
or tr
, it will fallback to tr
since fallbackLanguage is tr
.
Any help and suggestions would be great. Thank you.
Note: I included this gist by inamiy to encode / decode dictionaries and arrays.
Thanks to @AndyObusek, I've learned that there are nestedContainers
.
Here is the final solution for my problem:
// get localizedValues as nested container
let localizedValues = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.makeKey(name: "localizedValues")!)
var localizations: KeyedDecodingContainer<CodingKeys>
// if device locale identifier exists in the localizedValues container as a key get it as nested container, else get for fallbackLanguage.
if localizedValues.contains(CodingKeysmakeKey(name: Locale.current.identifier)!) {
localizations = try localizedValues.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.makeKey(name: Locale.current.identifier))
} else {
localizations = try localizedValues.nestedContainer(keyedBy: CodingKeys.self, forKey: CodingKeys.makeKey(name: fallbackLanguage))
}
// set description
description = try localizations.decode(String.self, forKey: CodingKeys.makeKey(name: "description"))
EDIT:
My data is a Cloud Firestore data, and I've found a great POD created by alickbass for encoding and decoding data for/from Firebase named CodableFirebase which is the simplest and best solution around if you use Firebase Database or Cloud Firestore