使用Codable解码JSON时可以吗?

编程入门 行业动态 更新时间:2024-10-05 23:22:37
本文介绍了使用Codable解码JSON时可以吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

使用Swift 3 JSONSerialization,如果您的数据模型的一部分是完全动态的,则始终可以将反序列化的数据保留在Any处,并让使用者处理它.

With Swift 3 JSONSerialization, if a part of your data model was completely dynamic, you could always just leave the deserialized data at Any and let the consumer deal with it.

使用Swift 4的Codable,我想这样做:

With Swift 4's Codable, I'd like to do this:

struct Foo : Codable { let bar: Any; }

但是我明白了

JSONPlayground.playground:4:9: note: cannot automatically synthesize 'Decodable' because 'Any' does not conform to 'Decodable' let bar: Any; ^

如果我可以实现自己的Decodable,那将不会是世界的尽头,但这将要求Decoder支持解码为Any,据我所知这还不是.例如:

That alone wouldn't be the end of the world if I could implement my own Decodable, but that would require the Decoder to support decoding to Any, which as far as I can tell it does not. For example:

extension Foo { init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let result = try container.decode(AnyClass.self) } }

给予

error: JSONPlayground.playground:4:36: error: cannot invoke 'decode' with an argument list of type '(AnyClass.Protocol)' let result = try container.decode(AnyClass.self) ^

对此有什么解决办法吗?

Is there any solution to this?

推荐答案

我最终不得不实现自己的类来对Any值进行编码/解码.它虽然不漂亮,但似乎可以正常工作:

I ended up having to implement my own class to encode/decode Any values. It's not pretty, but it seems to work:

class JSONAny: Codable { public let value: Any static func decodingError(forCodingPath codingPath: [CodingKey]) -> DecodingError { let context = DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot decode JSONAny") return DecodingError.typeMismatch(JSONAny.self, context) } static func encodingError(forValue value: Any, codingPath: [CodingKey]) -> EncodingError { let context = EncodingError.Context(codingPath: codingPath, debugDescription: "Cannot encode JSONAny") return EncodingError.invalidValue(value, context) } static func decode(from container: SingleValueDecodingContainer) throws -> Any { if let value = try? container.decode(Bool.self) { return value } if let value = try? container.decode(Int64.self) { return value } if let value = try? container.decode(Double.self) { return value } if let value = try? container.decode(String.self) { return value } if container.decodeNil() { return JSONNull() } throw decodingError(forCodingPath: container.codingPath) } static func decode(from container: inout UnkeyedDecodingContainer) throws -> Any { if let value = try? container.decode(Bool.self) { return value } if let value = try? container.decode(Int64.self) { return value } if let value = try? container.decode(Double.self) { return value } if let value = try? container.decode(String.self) { return value } if let value = try? container.decodeNil() { if value { return JSONNull() } } if var container = try? container.nestedUnkeyedContainer() { return try decodeArray(from: &container) } if var container = try? container.nestedContainer(keyedBy: MyCodingKey.self) { return try decodeDictionary(from: &container) } throw decodingError(forCodingPath: container.codingPath) } static func decode(from container: inout KeyedDecodingContainer, forKey key: MyCodingKey) throws -> Any { if let value = try? container.decode(Bool.self, forKey: key) { return value } if let value = try? container.decode(Int64.self, forKey: key) { return value } if let value = try? container.decode(Double.self, forKey: key) { return value } if let value = try? container.decode(String.self, forKey: key) { return value } if let value = try? container.decodeNil(forKey: key) { if value { return JSONNull() } } if var container = try? container.nestedUnkeyedContainer(forKey: key) { return try decodeArray(from: &container) } if var container = try? container.nestedContainer(keyedBy: MyCodingKey.self, forKey: key) { return try decodeDictionary(from: &container) } throw decodingError(forCodingPath: container.codingPath) } static func decodeArray(from container: inout UnkeyedDecodingContainer) throws -> [Any] { var arr: [Any] = [] while !container.isAtEnd { let value = try decode(from: &container) arr.append(value) } return arr } static func decodeDictionary(from container: inout KeyedDecodingContainer) throws -> [String: Any] { var dict = [String: Any]() for key in container.allKeys { let value = try decode(from: &container, forKey: key) dict[key.stringValue] = value } return dict } static func encode(to container: inout UnkeyedEncodingContainer, array: [Any]) throws { for value in array { if let value = value as? Bool { try container.encode(value) } else if let value = value as? Int64 { try container.encode(value) } else if let value = value as? Double { try container.encode(value) } else if let value = value as? String { try container.encode(value) } else if value is JSONNull { try container.encodeNil() } else if let value = value as? [Any] { var container = container.nestedUnkeyedContainer() try encode(to: &container, array: value) } else if let value = value as? [String: Any] { var container = container.nestedContainer(keyedBy: MyCodingKey.self) try encode(to: &container, dictionary: value) } else { throw encodingError(forValue: value, codingPath: container.codingPath) } } } static func encode(to container: inout KeyedEncodingContainer, dictionary: [String: Any]) throws { for (key, value) in dictionary { let key = MyCodingKey(stringValue: key)! if let value = value as? Bool { try container.encode(value, forKey: key) } else if let value = value as? Int64 { try container.encode(value, forKey: key) } else if let value = value as? Double { try container.encode(value, forKey: key) } else if let value = value as? String { try container.encode(value, forKey: key) } else if value is JSONNull { try container.encodeNil(forKey: key) } else if let value = value as? [Any] { var container = container.nestedUnkeyedContainer(forKey: key) try encode(to: &container, array: value) } else if let value = value as? [String: Any] { var container = container.nestedContainer(keyedBy: MyCodingKey.self, forKey: key) try encode(to: &container, dictionary: value) } else { throw encodingError(forValue: value, codingPath: container.codingPath) } } } static func encode(to container: inout SingleValueEncodingContainer, value: Any) throws { if let value = value as? Bool { try container.encode(value) } else if let value = value as? Int64 { try container.encode(value) } else if let value = value as? Double { try container.encode(value) } else if let value = value as? String { try container.encode(value) } else if value is JSONNull { try container.encodeNil() } else { throw encodingError(forValue: value, codingPath: container.codingPath) } } public required init(from decoder: Decoder) throws { if var arrayContainer = try? decoder.unkeyedContainer() { self.value = try JSONAny.decodeArray(from: &arrayContainer) } else if var container = try? decoder.container(keyedBy: MyCodingKey.self) { self.value = try JSONAny.decodeDictionary(from: &container) } else { let container = try decoder.singleValueContainer() self.value = try JSONAny.decode(from: container) } } public func encode(to encoder: Encoder) throws { if let arr = self.value as? [Any] { var container = encoder.unkeyedContainer() try JSONAny.encode(to: &container, array: arr) } else if let dict = self.value as? [String: Any] { var container = encoder.container(keyedBy: MyCodingKey.self) try JSONAny.encode(to: &container, dictionary: dict) } else { var container = encoder.singleValueContainer() try JSONAny.encode(to: &container, value: self.value) } } } class JSONNull: Codable { public init() { } public required init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if !container.decodeNil() { throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull")) } } public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encodeNil() } } class MyCodingKey : CodingKey { let key: String required init?(intValue: Int) { return nil } required init?(stringValue: String) { key = stringValue } var intValue: Int? { return nil } var stringValue: String { return key } }

更多推荐

使用Codable解码JSON时可以吗?

本文发布于:2023-11-26 23:27:43,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1635643.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Codable   JSON

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!