swift - 快速解码 [字符串:任意]
问题描述
所以我有这个返回字典的API [String: Any]
,我知道Any是什么Decodable
或一个数组,Decodable
但是我一生都无法弄清楚如何获取该字典并将其解码为某个结构:
我所拥有的基本上是这样的:
public func call<T: Codable> (completion handler: @escaping (T?) -> ()) {
let promise = api.getPromise ()
promise.done (on: DispatchQueue.main, { (results: [String:Any])
let decodedResults:T? = results.decode (as: T.self) // <-- this is what I want
handler (decodedResults)
})
}
我尝试将其转换为数据,然后使用以下命令对其进行解码:
let values = results.compactMap { $0.value }
let data = JSONSerialization.data (withJSONObject: values, options: [])
let decodedResult = JSONDecoder().decode(T.self, from: data)
但它总是失败NSInvalidArgumentException
,知道如何解决这个问题吗?
我试图实现但未能做到的另一件事是将值转换为元组,但我发现动态创建元组是不可能的。
解决方案
解码器将数据转换为可解码值。它们与[String: Any]
类型或任何其他非数据类型没有任何关系。所以如果你想通过解码器运行它,你需要将它转换为 JSON 编码成 Data。
如果[String: Any]
结果完全是 JSONSerialization 安全类型(数组、字典、字符串、数字、null),那么JSONSerialization.data(withJSONObject:options:)
您可以返回数据,以便重新解码。您的代码不仅重新编码其结果,它首先将其转换为一个数组:
let values = results.compactMap { $0.value }
let data = JSONSerialization.data (withJSONObject: values, options: [])
这很奇怪。您真的是要在这里创建一个数组并扔掉键吗?然后,我希望您的JSONDecoder().decode()
线路能够解码[T].self
而不是T.self
. 所以我希望下面的代码(假设你[String: Any]
是 JSON 安全的):
public func call<T: Decodable>(completion handler: @escaping (T?) -> ()) {
let promise = api.getPromise()
promise.done(on: .main) { (results: [String:Any]) in
guard JSONSerialization.isValidJSONObject(results) else {
handler(nil)
return
}
let data = JSONSerialization.data(withJSONObject: results)
let decodedResults = try? JSONDecoder().decode(T.self, from: data)
handler(decodedResults)
}
}
在评论中,您注意到解码数据([String: Any]
)不是由原语组成的。在这种情况下,无法使用 JSONSerialization 对其进行重新编码。您需要将 传递[String: Any]
给知道如何处理它的东西。例如:
protocol DictionaryDecodable {
init?(dictionary: [String: Any])
}
public func call<T: DictionaryDecodable>(completion handler: @escaping (T?) -> ()) {
let promise = api.getPromise ()
promise.done(on: .main) { (results: [String:Any])
handler(T.init(dictionary: results))
}
}
您的类型将需要实现一个init?(dictionary:)
可以从[String: Any]
.
推荐阅读
- mysql - 除非以 root 身份登录到 unix,否则无法登录 MySQL 命令行
- java - ListView 在滚动时崩溃
- java - Quarkus 中的 JAX-RS 子资源问题
- docker - 如何使“docker build”从上次失败的地方开始
- roku - Roku 上的 SetMaxVideoDecodeResolution 示例
- javascript - 相对定位元素内的绝对定位元素被剪裁
- java - 如何在 Spring Boot 中使用 Thymeleaf 将值传递给 HTML 模板的变量
- javascript - 如何将一行中的值复制到多次以下的空行?
- html - 为什么标签高度大于其内容?
- react-native - 无法在 react-native-pdf 中打开查看 PDF