json - 具有未知动态 key 的 Swift 4 可解码

标签 json swift decodable

我有以下 JSON

{"DynamicKey":6410,"Meta":{"name":"","page":""}}

DynamicKey 在编译时是未知的。我试图找到一个引用如何 使用 decodable 解析此结构。

public struct MyStruct: Decodable {
    public let unknown: Double
    public let meta: [String: String]

    private enum CodingKeys: String, CodingKey {
        case meta = "Meta"
    }
}

有什么想法吗?

最佳答案

要解码任意字符串,您需要这样的 key :

// Arbitrary key
private struct Key: CodingKey, Hashable, CustomStringConvertible {
    static let meta = Key(stringValue: "Meta")!

    var description: String {
        return stringValue
    }

    var hashValue: Int { return stringValue.hash }

    static func ==(lhs: Key, rhs: Key) -> Bool {
        return lhs.stringValue == rhs.stringValue
    }

    let stringValue: String
    init(_ string: String) { self.stringValue = string }
    init?(stringValue: String) { self.init(stringValue) }
    var intValue: Int? { return nil }
    init?(intValue: Int) { return nil }
}

这是一个非常通用的工具(static let meta 除外),可用于各种通用键问题。

有了它,您可以找到不是 .meta 的第一个 key ,并将其用作您的动态 key 。

public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: Key.self)

    meta = try container.decode([String: String].self, forKey: .meta)

    guard let dynamicKey = container.allKeys.first(where: { $0 != .meta }) else {
        throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [],
                                                                debugDescription: "Could not find dynamic key"))
    }

    unknown = try container.decode(Double.self, forKey: dynamicKey)
}

一起作为 Playground :

import Foundation

let json = Data("""
{"DynamicKey":6410,"Meta":{"name":"","page":""}}
""".utf8)

public struct MyStruct: Decodable {
    public let unknown: Double
    public let meta: [String: String]

    // Arbitrary key
    private struct Key: CodingKey, Hashable, CustomStringConvertible {
        static let meta = Key(stringValue: "Meta")!
        var description: String {
            return stringValue
        }

        var hashValue: Int { return stringValue.hash }

        static func ==(lhs: Key, rhs: Key) -> Bool {
            return lhs.stringValue == rhs.stringValue
        }

        let stringValue: String
        init(_ string: String) { self.stringValue = string }
        init?(stringValue: String) { self.init(stringValue) }
        var intValue: Int? { return nil }
        init?(intValue: Int) { return nil }
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: Key.self)

        meta = try container.decode([String: String].self, forKey: .meta)

        guard let dynamicKey = container.allKeys.first(where: { $0 != .meta }) else {
            throw DecodingError.dataCorrupted(.init(codingPath: [],
                                                    debugDescription: "Could not find dynamic key"))
        }

        unknown = try container.decode(Double.self, forKey: dynamicKey)
    }
}


let myStruct = try! JSONDecoder().decode(MyStruct.self, from: json)
myStruct.unknown
myStruct.meta

此技术可以扩展到 decode arbitrary JSON .有时这样做更容易,然后拉出你想要的片段,然后解码每个片段。例如,对于上面的 JSON 要点,您可以这样实现 MyStruct:

public struct MyStruct: Decodable {
    public let unknown: Double
    public let meta: [String: String]

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let json = try container.decode(JSON.self)

        guard let meta = json["Meta"]?.dictionaryValue as? [String: String] else {
            throw DecodingError.dataCorrupted(.init(codingPath: [],
                                                    debugDescription: "Could not find meta key"))
        }
        self.meta = meta

        guard let (_, unknownJSON) = json.objectValue?.first(where: { (key, _) in key != "Meta" }),
            let unknown = unknownJSON.doubleValue
        else {
            throw DecodingError.dataCorrupted(.init(codingPath: [],
                                                    debugDescription: "Could not find dynamic key"))
        }
        self.unknown = unknown
    }
}

关于json - 具有未知动态 key 的 Swift 4 可解码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53268833/

相关文章:

json - JQ:如何基于正则表达式过滤器从数组中删除对象?

ios - 升级后Alamofire 'invalid type in JSON write'错误

swift - 如何转换 Swift Bool? -> 字符串?

json - 使用 swift Codable 从 JSON 数组中提取数据

swift - 可编码 : does not conform to protocol 'Decodable'

Swift 可编码、可解码与可编码

javascript - 如何通过 php 将正则表达式变量保存为 .json 文件?

ios - CoreData 获取嵌套对象

ios - 如何放置 Admob 智能横幅?

ios - Firebase REST API - 如何观察和监听变化