所以我有这个返回 [String: Any]
字典的 API,我知道 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 安全类型(数组、字典、字符串、数字、空值),那么 JSONSerialization.data(withJSONObject:options:)
会让您返回数据,因此您可以重新解码它。你的代码不只是重新编码它的结果,它首先把它变成一个数组:
let values = results.compactMap { $0.value }
let data = JSONSerialization.data (withJSONObject: values, options: [])
这很奇怪。你真的想在这里创建一个数组并扔掉 key 吗?然后我希望你的
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]
中解码出它们自己的值。关于Swift 解码 [字符串 : Any],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55047138/