Swift解码[String:Any] [英] Swift Decode [String: Any]
问题描述
所以我有这个API,它返回 [String:Any]
的字典,我知道Any就是 Decodable
或 Decodable
的数组,但是我一辈子都无法弄清楚如何使用该字典并将其解码为某种结构:
So I have this API that returns a dictionary of [String: Any]
, I know that what comes as Any is Decodable
or an array of Decodable
however I can't for the life of me figure out how to take that dictionary and decode it to some struct:
我所拥有的基本上是这样的:
What I have goes basically like this:
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)
})
}
我尝试将其转换为数据,然后使用以下命令对其进行解码:
I've tried turning it to data and then decoding it with:
let values = results.compactMap { $0.value }
let data = JSONSerialization.data (withJSONObject: values, options: [])
let decodedResult = JSONDecoder().decode(T.self, from: data)
但是它总是由于 NSInvalidArgumentException
而失败,不知道如何解决这个问题?
but it always fails with NSInvalidArgumentException
, any idea how to get around this?
我正在尝试的另一件事实现但未能做到的是将值转换为元组,但就我所知,不可能动态创建元组。
Another thing that I was trying to achieve but failed to do so is to turn values into a tuple, but for all I could find it's not possible to create tuples dynamically.
推荐答案
解码器转换数据变为可分解值。它们与 [String:Any]
类型或任何其他非Data类型无关。因此,如果要通过解码器运行它,则需要将其转换为编码为Data的JSON。
Decoders convert Data into Decodable values. They don't have anything to do with [String: Any]
types or any other non-Data type. So if you want to run it through a decoder, you need to convert it to JSON encoded into Data.
如果 [String:Any]
结果仅是JSONSerialization安全类型(数组,字典,字符串,数字,空值),然后 JSONSerialization.data(withJSONObject:options:)
让您恢复数据,以便重新解码。您的代码不仅会重新编码结果,还会首先将其转换为数组:
If the [String: Any]
results are exclusively JSONSerialization-safe types (arrays, dictionaries, strings, numbers, null), then JSONSerialization.data(withJSONObject:options:)
would let you get back to data, so you can re-decode it. Your code doesn't just re-encode its results, it first turns it into an array:
let values = results.compactMap { $0.value }
let data = JSONSerialization.data (withJSONObject: values, options: [])
这很奇怪。您真的要在这里创建一个数组并扔掉键吗?然后,我希望您的 JSONDecoder()。decode()
行能够解码 [T] .self
而不是 T.self
。因此,我期望下面的代码(假设您的 [String:Any]
是JSON安全的):
That's very strange. Do you really mean to create an array here and throw away the keys? I would then expect your JSONDecoder().decode()
line to decode [T].self
rather than T.self
. So I would expect the following code (provided that your [String: Any]
is JSON-safe):
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]
传递给知道如何处理的东西。例如:
In the comments you note that the decoded data (the [String: Any]
) is not made of primitives. In that case it's not possible to re-encode it with JSONSerialization. You'll need to pass the [String: Any]
to something that knows how to deal with it. For example:
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?(字典:)
从 [String:Any]
解码自己的值。
Your types will need to implement an init?(dictionary:)
that can decode their own values out of a [String: Any]
.
这篇关于Swift解码[String:Any]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!