微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

我想在 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.

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐