我正在尝试将数据解码为结构体。以下是我的一个数据结构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"
}
}
}
此JSON对象的结构是:
struct X {
let name: String
let owner: String
let fallbackLanguage: String
let description: String
}
解码name
,owner
和fallbackLanguage
不是问题,已经完成。这是当前的CodingKey
和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`
}
问题是解码description
,因为它在多级字典中保存,并且它的值会因设备区域设置而改变。
在此示例中,如果设备区域设置不是en
,de
或tr
,则由于fallbackLanguage为tr
,它将回退到tr
。
任何帮助和建议都会很棒。谢谢。
答案 0 :(得分:2)
我建议为localizedValues
创建一个结构,并将该值解码为字典。然后获取当前fallbackLanguage
并从字典中获取相应的描述。
let jsonString = """
{ "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"}
}
}
"""
struct X : Decodable {
let name: String
let owner: String
let fallbackLanguage: String
let localizedValues: [String:LocalizedValue]
}
struct LocalizedValue : Decodable {
let description : String
}
let data = Data(jsonString.utf8)
do {
let result = try JSONDecoder().decode(X.self, from: data)
let fallBackLanguage = result.fallbackLanguage
let fallBackLanguageDescription = result.localizedValues[fallBackLanguage]?.description
print(fallBackLanguageDescription)
} catch { print(error)}
答案 1 :(得分:2)
感谢@AndyObusek,我了解到有nestedContainers
。
以下是我的问题的最终解决方案:
// 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"))
编辑:
我的数据是 Cloud Firestore 数据,我发现 alickbass 创建了一个很棒的POD,用于编码和解码名为{{3}的Firebase的数据如果您使用Firebase数据库或Cloud Firestore,这是最简单和最佳的解决方案
答案 2 :(得分:2)
您可以使用this extension进行编码和解码Array<Any>
和Dictionary<String: Any>
struct X: Decodable {
private enum CodingKeys: String, CodingKey {
case name, owner, fallbackLanguage, localizedValues
}
let name: String?
let owner: String?
let fallbackLanguage: String?
let localizedValues: Dictionary<String, Any>?
init(from decoder: Decoder) throws {
let container = try? decoder.container(keyedBy: CodingKeys.self)
name = try container?.decodeIfPresent(String.self, forKey: .name)
owner = try container?.decodeIfPresent(String.self, forKey: .owner)
fallbackLanguage = try container?.decodeIfPresent(String.self, forKey: .fallbackLanguage)
localizedValues = try container?.decodeIfPresent(Dictionary<String, Any>.self, forKey: .localizedValues)
}
}
答案 3 :(得分:0)
使用您的json,您可以创建以下结构
SELECT
Col1,
Col2,
Col3,
coalesce(Col3, Col2) AS Col4
FROM table1
并像这样使用
struct LocalizedJSONObject: Codable {
let name, owner, fallbackLanguage: String?
let localizedValues: LocalizedValues?
}
struct LocalizedValues: Codable {
let en, de, tr: De?
}
struct De: Codable {
let description: String?
}
// MARK: Convenience initializers
extension LocalizedJSONObject {
init(data: Data) throws {
self = try JSONDecoder().decode(LocalizedJSONObject.self, from: data)
}
init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func jsonData() throws -> Data {
return try JSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
extension LocalizedValues {
init(data: Data) throws {
self = try JSONDecoder().decode(LocalizedValues.self, from: data)
}
init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func jsonData() throws -> Data {
return try JSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
extension De {
init(data: Data) throws {
self = try JSONDecoder().decode(De.self, from: data)
}
init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func jsonData() throws -> Data {
return try JSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
答案 4 :(得分:0)
如果您没有按计划进行操作,请为此库提供一个镜头:Swifty Json
它有一些内置的方法可以抽象你的需求,例如将嵌套字典Json对象转换为NSDictionary,在那里你可以提取值并在它们上面应用控制流来构建逻辑。