在 swift 中对动态键和动态对象使用 Codable
Using Codable on a dynamic key and dynamic object in swift
我将以下结构嵌套在从服务调用返回的结构中,但我无法 encode/decode 这部分。我遇到的问题是 customKey 和 customValue 都是动态的。 customValue 可以是数组或字典或字典数组
例如
{
"status": "a string value",
"id": "a string value",
"property": {
"customkey1": "customValue1",
"customKey2": [{
"InnerCustomKey": "InnerCustomValue"
}, {
"InnerCustomKey": "InnerCustomValue"
}, {
"InnerCustomKey": "InnerCustomValue"
}],
"customkey3": {
"InnerCustomKey": "InnerCustomValue"
}
}
}
我尝试了类似 var values: [String:String] 的方法,但它在另一个对象中失败了。
我按照答案 但没有成功
extension KeyedDecodingContainerProtocol{
func getValueFromAvailableKey(codingKeys:[CodingKey])-> Any?{
for key in codingKeys{
for keyPath in self.allKeys{
if key.stringValue == keyPath.stringValue{
do{
if let value = try? self.decodeIfPresent([String].self, forKey:keyPath){
return value
}
if let value = try? self.decodeIfPresent([String:String].self, forKey:keyPath){
return value
}
if let value = try? self.decodeIfPresent([[String:String]].self, forKey:keyPath){
return value
}
if let value = try? self.decodeIfPresent(String.self, forKey:keyPath){
return value
}
return nil
}
}
}
}
return nil
}
}
private struct CustomCodingKeys: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
return nil
}
}
struct CustomModel: Codable {
var status:String?
var id: String?
var property: Property?
init(from decoder: Decoder) {
do{
let container = try decoder.container(keyedBy: CustomCodingKeys.self)
status = try container.decodeIfPresent(String.self, forKey: CustomCodingKeys.init(stringValue: "status")!)
id = try container.decodeIfPresent(String.self, forKey: CustomCodingKeys.init(stringValue: "id")!)
property = try container.decodeIfPresent(Property.self, forKey: CustomCodingKeys.init(stringValue: "property")!)
}catch{
print(error.localizedDescription)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CustomCodingKeys.self)
try? container.encodeIfPresent(self.status, forKey: CustomCodingKeys.init(stringValue: "status")!)
try? container.encodeIfPresent(self.id, forKey: CustomCodingKeys.init(stringValue: "id")!)
try? container.encodeIfPresent(self.property, forKey: CustomCodingKeys.init(stringValue: "property")!)
}
}
// MARK: - Property
struct Property: Codable {
var customkey:[String:Any?] = [:]
init(from decoder: Decoder) {
do{
let container = try decoder.container(keyedBy: CustomCodingKeys.self)
for key in container.allKeys{
customkey[key.stringValue] = container.getValueFromAvailableKey(codingKeys: [CustomCodingKeys.init(stringValue: key.stringValue)!])
}
}catch{
print(error.localizedDescription)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CustomCodingKeys.self)
for key in customkey{
try? container.encodeIfPresent(customkey[key.key] as? String, forKey: CustomCodingKeys.init(stringValue: key.key)!)
try? container.encodeIfPresent(customkey[key.key] as? [[String:String]], forKey: CustomCodingKeys.init(stringValue: key.key)!)
try? container.encodeIfPresent(customkey[key.key] as? [String:String], forKey: CustomCodingKeys.init(stringValue: key.key)!)
}
}
}
希望对您有所帮助!
我将以下结构嵌套在从服务调用返回的结构中,但我无法 encode/decode 这部分。我遇到的问题是 customKey 和 customValue 都是动态的。 customValue 可以是数组或字典或字典数组 例如
{
"status": "a string value",
"id": "a string value",
"property": {
"customkey1": "customValue1",
"customKey2": [{
"InnerCustomKey": "InnerCustomValue"
}, {
"InnerCustomKey": "InnerCustomValue"
}, {
"InnerCustomKey": "InnerCustomValue"
}],
"customkey3": {
"InnerCustomKey": "InnerCustomValue"
}
}
}
我尝试了类似 var values: [String:String] 的方法,但它在另一个对象中失败了。
我按照答案
extension KeyedDecodingContainerProtocol{
func getValueFromAvailableKey(codingKeys:[CodingKey])-> Any?{
for key in codingKeys{
for keyPath in self.allKeys{
if key.stringValue == keyPath.stringValue{
do{
if let value = try? self.decodeIfPresent([String].self, forKey:keyPath){
return value
}
if let value = try? self.decodeIfPresent([String:String].self, forKey:keyPath){
return value
}
if let value = try? self.decodeIfPresent([[String:String]].self, forKey:keyPath){
return value
}
if let value = try? self.decodeIfPresent(String.self, forKey:keyPath){
return value
}
return nil
}
}
}
}
return nil
}
}
private struct CustomCodingKeys: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
return nil
}
}
struct CustomModel: Codable {
var status:String?
var id: String?
var property: Property?
init(from decoder: Decoder) {
do{
let container = try decoder.container(keyedBy: CustomCodingKeys.self)
status = try container.decodeIfPresent(String.self, forKey: CustomCodingKeys.init(stringValue: "status")!)
id = try container.decodeIfPresent(String.self, forKey: CustomCodingKeys.init(stringValue: "id")!)
property = try container.decodeIfPresent(Property.self, forKey: CustomCodingKeys.init(stringValue: "property")!)
}catch{
print(error.localizedDescription)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CustomCodingKeys.self)
try? container.encodeIfPresent(self.status, forKey: CustomCodingKeys.init(stringValue: "status")!)
try? container.encodeIfPresent(self.id, forKey: CustomCodingKeys.init(stringValue: "id")!)
try? container.encodeIfPresent(self.property, forKey: CustomCodingKeys.init(stringValue: "property")!)
}
}
// MARK: - Property
struct Property: Codable {
var customkey:[String:Any?] = [:]
init(from decoder: Decoder) {
do{
let container = try decoder.container(keyedBy: CustomCodingKeys.self)
for key in container.allKeys{
customkey[key.stringValue] = container.getValueFromAvailableKey(codingKeys: [CustomCodingKeys.init(stringValue: key.stringValue)!])
}
}catch{
print(error.localizedDescription)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CustomCodingKeys.self)
for key in customkey{
try? container.encodeIfPresent(customkey[key.key] as? String, forKey: CustomCodingKeys.init(stringValue: key.key)!)
try? container.encodeIfPresent(customkey[key.key] as? [[String:String]], forKey: CustomCodingKeys.init(stringValue: key.key)!)
try? container.encodeIfPresent(customkey[key.key] as? [String:String], forKey: CustomCodingKeys.init(stringValue: key.key)!)
}
}
}
希望对您有所帮助!