当前位置 : 主页 > 手机开发 > 其它 >

如何在Swift中表示通用的JSON结构?

来源:互联网 收集:自由互联 发布时间:2021-06-11
我想在 Swift中表示一个通用的JSON对象: let foo: [String: Any] = [ "foo": 1, "bar": "baz",] 但编译器建议的[String:Any]类型并不能很好地工作.我无法检查该类型的两个实例是否相等,例如,虽然这应
我想在 Swift中表示一个通用的JSON对象:

let foo: [String: Any] = [
    "foo": 1,
    "bar": "baz",
]

但编译器建议的[String:Any]类型并不能很好地工作.我无法检查该类型的两个实例是否相等,例如,虽然这应该可以使用两个JSON树.

什么也行不通的是使用Codable机制将该值编码为JSON字符串:

let encoded = try JSONEncoder().encode(foo)

哪个因错误而爆炸:

fatal error: Dictionary<String, Any> does not conform to Encodable because Any does not conform to Encodable.

我知道我可以引入一个精确的类型,但我遵循通用的JSON结构.我甚至尝试为泛型JSON引入一种特定类型:

enum JSON {
    case string(String)
    case number(Float)
    case object([String:JSON])
    case array([JSON])
    case bool(Bool)
    case null
}

但是当为这个枚举实现Codable时,我不知道如何实现encode(to :),因为一个带键的容器(用于编码对象)需要一个特定的CodingKey参数,我不知道如何获得它.

是否真的不可能创建一个Equatable通用JSON树并使用Codable对其进行编码?

我们将使用通用字符串作为编码键:

extension String: CodingKey {
    public init?(stringValue: String) {
        self = stringValue
    }

    public var stringValue: String {
        return self
    }

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

    public var intValue: Int? {
        return nil
    }
}

剩下的只是获取正确类型的容器并将值写入其中.

extension JSON: Encodable {
    public func encode(to encoder: Encoder) throws {
        switch self {
        case .string(let string):
            var container = encoder.singleValueContainer()
            try container.encode(string)
        case .number(let number):
            var container = encoder.singleValueContainer()
            try container.encode(number)
        case .object(let object):
            var container = encoder.container(keyedBy: String.self)

            for (key, value) in object {
                try container.encode(value, forKey: key)
            }
        case .array(let array):
            var container = encoder.unkeyedContainer()

            for value in array {
                try container.encode(value)
            }
        case .bool(let bool):
            var container = encoder.singleValueContainer()
            try container.encode(bool)
        case .null:
            var container = encoder.singleValueContainer()
            try container.encodeNil()
        }
    }
}

鉴于此,我相信你可以自己实现Decodable和Equatable.

请注意,如果您尝试将除数组或对象之外的任何内容编码为顶级元素,则会崩溃.

网友评论