ios - 在 swift 中对动态键和动态对象使用 Codable

标签 ios swift swift5

我将以下结构嵌套在从服务调用返回的结构中,但我无法设法对这部分进行编码/解码。我遇到的问题是 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] 的方法,但它在另一个对象中失败了。 我按照答案Using Codable on a dynamic type/object但没有取得成功

最佳答案

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)!)
            }

    }
}

希望对您有所帮助!

关于ios - 在 swift 中对动态键和动态对象使用 Codable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58878276/

相关文章:

arrays - Swift - 如何在 swiftUI 中将字符串数组添加到我的 ListView

objective-c - 一个 Controller 来统治他们

ios - 使用自动布局时自动调整 UILabel 的大小

ios - Swift 字典 UIPickerView (键)和 UITableView (值)

ios - 当外部 scrollview 开始滚动时增加 tableview 高度

ios - 当整数不是 0、1 或 2 时程序崩溃

macos - 在 macOS 的 Swift 5.x 中设置证书信任

swift - 如何在 Swift 5 中遍历字典?

ios - iOS 11 上的 WKWebView 支持 .heic 图像吗?

swift - 顶层不允许使用表达式