Swift JSON 具有不同值的解码器
Swift JSON decoder with different values
我想解码具有不同值的字典。因此,虽然键始终是 String
类型,但值将具有相同的 superclass
(如 Shape
)但可能由不同的 subclasses
(如 Rectangle
, Circle
).我希望稍后能够检查附加了哪个 subclass
,但到目前为止我只能使用默认解码为 [ AttachedObject: Shape ]
.
看例子:
enum AttachedObject: String, Codable {
case chair
case lamp
case desk
}
class Shape: Codable {
var name: String
init(name: String) {
self.name = name
}
}
class Rectangle: Shape {
var width: Double
var height: Double
init(name: String, width: Double, height: Double) {
self.width = width
self.height = height
super.init(name: name)
}
enum CodingKeys: String, CodingKey {
case width
case height
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.height, forKey: .height)
}
required public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.width = try values.decode(Double.self, forKey: .width)
self.height = try values.decode(Double.self, forKey: .height)
try super.init(from: decoder)
}
}
class Circle: Shape {
var radius: Double
init(name: String, radius: Double) {
self.radius = radius
super.init(name: name)
}
enum CodingKeys: String, CodingKey {
case radius
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.radius, forKey: .radius)
}
required public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.radius = try values.decode(Double.self, forKey: .radius)
try super.init(from: decoder)
}
}
class MyRoom: Codable {
public var attachedShapes: [ AttachedObject: Shape ]
enum CodingKeys: String, CodingKey {
case attachedShapes
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.attachedShapes, forKey: .attachedShapes)
}
required public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
fatalError("// How to handle the decoding part?")
}
}
我会选择这样的东西:
enum ShapeType: String, RawRepresentable, Codable {
// Required for RawRepresentable
static var defaultDecoderValue: ShapeType = .circle
case circle
case rectangle
}
struct Shape: Codable {
let name: String
let width: Double?
let height: Double?
let radius: Double?
let type: ShapeType
}
那么您不需要任何自定义键。您始终可以引用数组中的任何 Shape,等等。您可以查看 ShapeType 以查看它是矩形还是圆形。如果您需要更改它们,您可以将它们设为 var 而不是 let,如果您想要 class,则可以设为 is Class Shape 而不是 Struct Shape。
我想解码具有不同值的字典。因此,虽然键始终是 String
类型,但值将具有相同的 superclass
(如 Shape
)但可能由不同的 subclasses
(如 Rectangle
, Circle
).我希望稍后能够检查附加了哪个 subclass
,但到目前为止我只能使用默认解码为 [ AttachedObject: Shape ]
.
看例子:
enum AttachedObject: String, Codable {
case chair
case lamp
case desk
}
class Shape: Codable {
var name: String
init(name: String) {
self.name = name
}
}
class Rectangle: Shape {
var width: Double
var height: Double
init(name: String, width: Double, height: Double) {
self.width = width
self.height = height
super.init(name: name)
}
enum CodingKeys: String, CodingKey {
case width
case height
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.height, forKey: .height)
}
required public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.width = try values.decode(Double.self, forKey: .width)
self.height = try values.decode(Double.self, forKey: .height)
try super.init(from: decoder)
}
}
class Circle: Shape {
var radius: Double
init(name: String, radius: Double) {
self.radius = radius
super.init(name: name)
}
enum CodingKeys: String, CodingKey {
case radius
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.radius, forKey: .radius)
}
required public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.radius = try values.decode(Double.self, forKey: .radius)
try super.init(from: decoder)
}
}
class MyRoom: Codable {
public var attachedShapes: [ AttachedObject: Shape ]
enum CodingKeys: String, CodingKey {
case attachedShapes
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.attachedShapes, forKey: .attachedShapes)
}
required public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
fatalError("// How to handle the decoding part?")
}
}
我会选择这样的东西:
enum ShapeType: String, RawRepresentable, Codable {
// Required for RawRepresentable
static var defaultDecoderValue: ShapeType = .circle
case circle
case rectangle
}
struct Shape: Codable {
let name: String
let width: Double?
let height: Double?
let radius: Double?
let type: ShapeType
}
那么您不需要任何自定义键。您始终可以引用数组中的任何 Shape,等等。您可以查看 ShapeType 以查看它是矩形还是圆形。如果您需要更改它们,您可以将它们设为 var 而不是 let,如果您想要 class,则可以设为 is Class Shape 而不是 Struct Shape。