首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >可快速编码:如何“通过”未分析的json子对象

可快速编码:如何“通过”未分析的json子对象
EN

Stack Overflow用户
提问于 2019-01-08 08:09:33
回答 3查看 1.2K关注 0票数 2

由于复杂的原因,我发现自己在反对Codable:在解码json对象时,我希望将子对象保存在键extra下,“就像json一样”,存储在[String: Any]字典中,但[String: Any]当然不是Decodable。有办法这样做吗?

第一个答案当然是“不要”。对此,我的响应是“我需要去做”:我需要让两个Codable传递数据,其中第一个解码一个异构对象的列表(每个对象都有一个键name),而第二次传递使用一个按这些name值键键的字典,并且是正确的类型安全的。第一次传递不能是类型安全的,因为它是在异构列表上操作的,但是它需要保存第二次传递将处理的所有数据。谢天谢地,所有的异构数据都隐藏在这个extra键下,但我仍然不知道该如何做。

(关于_en_coding,很可能会有一个类似的问题,所以如果你碰巧有洞察力,那就随便提吧。)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-01-08 23:31:55

这个Swift论坛帖子似乎提供了一个解决方案。它是这样开始的:

代码语言:javascript
运行
复制
public enum JSON : Codable {
    case null
    case number(NSNumber)
    case string(String)
    case array([JSON])
    case dictionary([String : JSON])
    // ...

其思想是使显式的JSON枚举类型,即Codable,直接编码json结构(case string(String); case array([JSON]);等)。未分析的子对象被强类型为JSON,可以通过Codable进行编码/解码,并且(作为奖励)还可以使用"just Swift“(打开情况并做一些事情)进行必要的分析。

票数 0
EN

Stack Overflow用户

发布于 2019-01-08 10:45:15

您可以创建一个自定义字典Decodable,它对Dictionary中的值进行解码和存储,然后对要存储原始字典的键使用此类型。

这是可解码的:

代码语言:javascript
运行
复制
struct DictionaryDecodable: Decodable {

    let dictionary : [String: Any]

    private struct Key : CodingKey {

        var stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }

        var intValue: Int?
        init?(intValue: Int) {
            return nil
        }
    }

    init(from decoder: Decoder) throws {
        let con = try decoder.container(keyedBy: Key.self)
        var dict = [String: Any]()
        for key in con.allKeys {
            if let value = try? con.decode(String.self, forKey:key) {
                dict[key.stringValue] = value
            } else if let value = try? con.decode(Int.self, forKey:key) {
                dict[key.stringValue] = value
            } else if let value = try? con.decode(Double.self, forKey:key) {
                dict[key.stringValue] = value
            } else if let value = try? con.decode(Bool.self, forKey:key) {
                dict[key.stringValue] = value
            } else if let data = try? con.decode(DictionaryDecodable.self, forKey:key)  {
                dict[key.stringValue] = data.dictionary
            }

        }
        self.dictionary = dict
    }
}

现在,您可以使用这个结构来解码字典,如下所示:

代码语言:javascript
运行
复制
struct Test: Decodable {
    let name: String
    let data: [String: Any]

    enum Keys: String, CodingKey {
        case name
        case data
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: Keys.self)
        name = try container.decode(String.self, forKey: .name)
        data = try container.decode(DictionaryDecodable.self, forKey: .data).dictionary // Here use DictionaryDecodable
    }
}

让我们来测试:

代码语言:javascript
运行
复制
let data = """
{
    "name": "name",
    "data": {
        "string": "rt",
        "bool": true,
        "float": 1.12,
        "int": 1,
        "dict": {
            "test": "String"
        }
    }
}
"""

let s = try JSONDecoder().decode(Test.self, from: data.data(using: .utf8)!)
print(s.name)
print(s.data)

这是输出:

代码语言:javascript
运行
复制
name
["bool": true, "string": "rt", "int": 1, "float": 1.12, "dict": ["test": "String"]]
票数 4
EN

Stack Overflow用户

发布于 2019-01-08 10:21:17

我得到的最接近的是以下操场代码:

代码语言:javascript
运行
复制
struct Foo: Codable {
    let bar: [String: Any]

    enum CodingKeys: String, CodingKey {
        case bar
    }

    init(bar: [String: Any]) {
        self.bar = bar
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        let barString = try values.decode(String.self, forKey: .bar)
        let barData = Data(barString.utf8)
        let json: [String: Any] = try JSONSerialization.jsonObject(with: barData, options: .allowFragments) as! [String: Any]
        bar = json
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        let barData = try JSONSerialization.data(withJSONObject: bar, options: .sortedKeys)
        let barString = String(decoding: barData, as: UTF8.self)
        try container.encode(barString, forKey: .bar)
    }
}

let foo = Foo(bar: ["someInt": 1])
let fooData = try! JSONEncoder().encode(foo)
print(String(decoding: fooData, as: UTF8.self))
print(String(decoding: fooData, as: UTF8.self).replacingOccurrences(of: "\\\"", with: "\""))

let decodedFoo = try! JSONDecoder().decode(Foo.self, from: fooData)
print(decodedFoo)

上述指纹:

代码语言:javascript
运行
复制
{"bar":"{\"someInt\":1}"}
{"bar":"{"someInt":1}"}
Foo(bar: ["someInt": 1])

它还不完美,因为它在生成的JSON字符串中转义了",因此可能会破坏其中的一些内容。额外的字符串替换传递可能不是什么令人愉快的事情。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54087588

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档