0

我需要获取整个字典作为键“内容”的字符串。我将它作为 nil 接收。我尝试使用 [String:Any] 抛出异常,无法确认任何可解码

public static func getModelObjects<R: Codable>(_ type: R.Type, from data: Any?) -> [T]? {
        var mappedObjects: [T]?
        if let dataAsDic = data as? JSONDictionary {
            let decodedObject = decodableData(type, dictionaryData: dataAsDic)
            mappedObjects = [decodedObject] as? [T]
        } else if let dataAsArray = data as? [JSONDictionary] {
            var objects: [R] = []
            for dataAsDic in dataAsArray {
                guard let decodedObject = decodableData(type, dictionaryData: dataAsDic) else {
                    return nil
                }
             objects.append(decodedObject)
            }
            mappedObjects = objects as? [T]
        }
        return mappedObjects
    }

    private static func decodableData<R: Codable>(_ type: R.Type, dictionaryData: JSONDictionary) -> R? {
            let decoder = JSONDecoder()
            do {
                let jsonData = try JSONSerialization.data(withJSONObject: dictionaryData, options: JSONSerialization.WritingOptions.prettyPrinted)
                let decodedData = try decoder.decode(type, from: jsonData)
                return decodedData
            } catch {
                return nil
            }
        }

    public class Configuration: CacheableEntity, ConfigurationStorageProtocol, Codable {
          public dynamic var configurationID: String!

            /// Version of configuration
            public dynamic var version: String!

            private var storedConfigDict: JSONDictionary?

            private var storedConfigData: Data?
              // Holds complete configuration as string

    dynamic var configString: String? 

                /// Codable keys to confirm Codable protocol
                private enum CodingKeys: String, CodingKey {
                    case configurationID = "id"
                    case version
                    case name
                    case content
                }

            public required init(from decoder: Decoder) throws {
                super.init()
                let container = try decoder.container(keyedBy: CodingKeys.self)
                self.name = try? container.decode(String.self, forKey: .name)
                self.configurationID = try? container.decode(String.self, forKey: .configurationID)
                self.version = try? container.decode(String.self, forKey: .version)
                self.configString = try? container.decode(String.self, forKey: .content)
            }

public func encode(to encoder: Encoder) throws {
    var  container = encoder.container(keyedBy: CodingKeys.self)
    try? container.encode(configurationID, forKey: .configurationID)
    try? container.encode(version, forKey: .version)
    try? container.encode(name, forKey: .name)
  }
}

在下面的 json 中,我需要将整个内容作为字符串获取。我尝试过使用 [String:Any] 但它崩溃了,因为它提到任何不能符合可解码。

"name": "sdkconfig",
    "id": "gma_5.0_ios_sdkconfig_1.0_us",
    "version": "1.0",
    "modifiedDateTime": "2017-06-15T08:15:25.304Z",
    "content": {
        "configName": "sdkConfig",
        "configVersion": "1.0",
        "enabled": {
            "modules": [
                        "account",
                        "nutrition",
                        "restaurant",
                        "offer",
                        "ordering",
                        "favorite"
                        ],
            "socialAccounts": [
                               "facebook",
                               "google",
                               "twitter"
                               ]
        }
}
4

2 回答 2

0

我不确定你的做法。但这就是我让它工作的方式。像这样定义你的类。

    struct Configuration: Codable {

        var content: String?
    }

属性名称和json中的名称必须相同。(在这种情况下是“有能力的”)。现在像这样解析你的 json 字符串。

    var configuration = JSONDecoder().decode(Configuration.self, from: "your json string")
于 2018-02-26T11:45:16.080 回答
0

尽管您的代码的流程和结构并不像其他人指出的那样清晰,但似乎您希望将JSONDictionary您拥有的内容编码为StringintoconfigString属性。我看到你正在解码configStringinit(from decoder: Decoder)

self.configString = try? container.decode(String.self, forKey: .content)

但你没有编码它,你的编码方法应该是:

public func encode(to encoder: Encoder) throws {
    var  container = encoder.container(keyedBy: CodingKeys.self)
    try? container.encode(configurationID, forKey: .configurationID)
    try? container.encode(version, forKey: .version)
    try? container.encode(name, forKey: .name)
    if let jsonStr = String(data: storedConfigData, encoding: .utf8) {
        try? container.encoder(jsonStr, forKey: .content)
    }
}

编辑:

我从你的问题中忽略了这个信息:

我曾尝试使用 [String:Any] 但它崩溃提到任何不能符合可解码

基本上解码器不知道如何解码Any,你需要提供一个特定的类型,在你的尝试以下init(decoder:)

init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.configurationID = try? container.decode(String.self, forKey: .configurationID)
        self.version = try? container.decode(String.self, forKey: .version)
        if let configDict = try? container.decode([String: String].self, forKey: .content) {
            self.configString = String(describing: configDict)
        }
    }

或者

如果您的内容是异构字典,上述方法将不起作用,因为您已经拥有字典数据,您可以使用它直接获取内容,如下所示,

config.configString = String(describing: dictionaryData[Config.CodingKeys.content.rawValue] as! JSONDictionary)
于 2018-02-26T12:05:37.827 回答