【问题标题】:Get class type dynamically from string for JSONDecoder.decode()从字符串中动态获取 JSONDecoder.decode() 的类类型
【发布时间】:2017-08-13 13:33:47
【问题描述】:

我想解码 websocket“通知”的 json 响应,其中通知类型在 json 响应中。

JSON 示例:

{
    "jsonrpc": "2.0",
    "method": "Application.OnVolumeChanged",
    "params": {
        "data": {
            "muted": false,
            "volume": 88.6131134033203125
        },
        "sender": "xbmc"
    }
}

这是我目前拥有的:

func notificationMessage(text: String) {
    do {
        if let jsonData = text.data(using: .utf8),
            let json = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any],
            let method = json["method"] as? String,
            let methodName = method.split(separator: ".").last?.description {

            let decoder = JSONDecoder()
            let object = try decoder.decode(OnVolumeChanged.self, from: jsonData)

            print(object)
        }
    } catch {
        print("Error deserializing JSON: \(error)")
    }
}

现在我想用methodName 代替OnVolumeChanged.self。 但我不想在 methodName 上做一个巨大的 switch case,因为我可以获得数百种不同的方法 我试过NSClassFromString(methodName),但这给了我AnyClass?,这不是一个具体的类型。

有没有办法从字符串中获取类类型?

【问题讨论】:

  • 你试过NSClassFromString(method)而不是剥离method字符串的命名空间部分吗?
  • decode() 期待具体类型 T.TypeAnyClass? 基本上是任何东西。
  • 这违背了 Swift 的静态类型系统,所以你将不得不逆流而上。但在你这样做之前,问问自己:你想为OnVolumeChangedAnotherMethodName 捕获任何区别吗?如果是这样,请编辑您的问题以添加示例。
  • 我在将 JSON 与类类型匹配时遇到了同样的问题,我最终使用了原始值与 JSON 字符串值匹配的枚举。
  • 是的@CodeDifferent,json 中的数据对象对于每种方法都是不同的。但我会坚持使用包含所有可能方法的枚举,然后使用 switch case 确定应该使用哪个对象来解码 json。感谢您的信息!

标签: swift swift4


【解决方案1】:

我遇到了同样的问题,这是我的解决方案。你可以加 任何时候映射字典的方法。

//1

let Mapper: [String: Any] = ["OnVolumeChanged"  : OnVolumeChanged.self]

//2

func notificationMessage(text: String) {
                    do {
                        if let jsonData = text.data(using: .utf8),
                            let json = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any],
                            let method = json["method"] as? String,
                            let methodName = method.split(separator: ".").last?.description {

                            let className = Mapper[methodName] as! Codable.Type
                            let object = try className.init(jsonData: jsonData)


                            print(object)
                        }
                    } catch {
                        print("Error deserializing JSON: \(error)")
                    }
                }

//3

extension Decodable {
                    init(jsonData: Data) throws {
                        self = try JSONDecoder().decode(Self.self, from: jsonData)
                    }
                }

【讨论】:

  • 这个解决方案没有什么“动态”,应该有一个解决方案,我们不需要手动输入我们为 json 响应自动生成的所有类,甚至提供“解码器”实用程序预期的 json 响应和做 Bundle.main.classNamed("MyClassName") 更好,(比如这里:stackoverflow.com/a/55170964/530884
猜你喜欢
  • 2011-01-25
  • 1970-01-01
  • 1970-01-01
  • 2016-10-24
  • 2023-03-13
  • 1970-01-01
  • 2011-01-06
  • 2014-01-01
相关资源
最近更新 更多