Swift解码[String:Any] [英] Swift Decode [String: Any]

查看:710
本文介绍了Swift解码[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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆