如何将多个对象类型的数组转换为 JSON 而不会丢失 Swift 中的任何对象属性?
How to convert an array of multiple object types to JSON without missing any object attribute in Swift?
在我的 iOS Swift 项目中,我需要将对象转换为 JSON。
我有一个简单的 class:
class Car : Encodable
{
var brand: String
init(brand: String)
{
self.brand = brand
}
}
和一个子class:
class SUVCar : Car
{
var weight: Int
init(_ weight: Int)
{
self.weight = weight
super.init(brand: "MyBrand")
}
}
我使用以下通用函数将对象和数组转换为 JSON:
func toJSON<T : Encodable>(_ object: T) -> String?
{
do
{
let jsonEncoder = JSONEncoder()
let jsonEncode = try jsonEncoder.encode(object)
return String(data: jsonEncode, encoding: .utf8)
}
catch
{
return nil
}
}
现在假设我想将以下变量转换为 JSON:
var arrayOfCars: Array<Car> = []
arrayOfCars.append(SUVCar(1700))
arrayOfCars.append(SUVCar(1650))
我使用 Array<Car>
作为该数组的类型,因为该数组中还有其他类型的汽车。为了便于阅读,我在这里简化了它。
这就是我所做的:
let json = toJSON(arrayOfCars)
但由于某些原因,当转换为 JSON 时,SUVCar
的 weight
属性被忽略,即使 arrayOfCars
包含 SUVCar
个对象,我得到一个看起来像这样的 JSON:
[{brand: "MyBrand"}, {brand: "MyBrand"}]
那么如何在我的 JSON 中获取 SUVCar
的 weight
属性?我错过了什么?
谢谢。
class SUVCar: Car
{
enum SUVCarKeys: CodingKey {
case weight
}
var weight: Int
init(_ weight: Int)
{
self.weight = weight
super.init(brand: "MyBrand")
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: SUVCarKeys.self)
try container.encode(weight, forKey: .weight)
try super.encode(to: encoder)
}
}
如果您扩充子类的编码实现,那么您可以添加额外的属性
与其自定义所有子classes 以正确编码,不如引入一种可以容纳不同类型汽车的类型来解决这个问题
struct CarCollection: Encodable {
let suvs: [SUVCar]
let jeeps: [Jeep]
let sedans: [Sedan]
}
(假设另外两个sublclasses class Jeep: Car {}
和class Sedan: Car {}
)
那么你就不需要额外的代码,编码也很简单
let cars = CarCollection(suvs: [SUVCar(brand: "x", weight: 1000)],
jeeps: [Jeep(brand: "y")],
sedans: [Sedan(brand: "z")])
if let json = toJSON(cars) {
print(json)
}
{"jeeps":[{"brand":"x"}],"suvs":[{"brand":"x"}],"sedans":[{"brand":"a"}]}
有点跑题了,但是 struct 可能是比 class 更好的选择,或者至少它是推荐的选择,所以这里是使用 struct 和协议而不是 superclass。上面的代码仍然是一样的。
protocol Car : Encodable {
var brand: String { get set }
}
struct SUVCar : Car {
var brand: String
var weight: Int
}
struct Jeep: Car {
var brand: String
}
struct Sedan: Car {
var brand: String
}
在我的 iOS Swift 项目中,我需要将对象转换为 JSON。
我有一个简单的 class:
class Car : Encodable
{
var brand: String
init(brand: String)
{
self.brand = brand
}
}
和一个子class:
class SUVCar : Car
{
var weight: Int
init(_ weight: Int)
{
self.weight = weight
super.init(brand: "MyBrand")
}
}
我使用以下通用函数将对象和数组转换为 JSON:
func toJSON<T : Encodable>(_ object: T) -> String?
{
do
{
let jsonEncoder = JSONEncoder()
let jsonEncode = try jsonEncoder.encode(object)
return String(data: jsonEncode, encoding: .utf8)
}
catch
{
return nil
}
}
现在假设我想将以下变量转换为 JSON:
var arrayOfCars: Array<Car> = []
arrayOfCars.append(SUVCar(1700))
arrayOfCars.append(SUVCar(1650))
我使用 Array<Car>
作为该数组的类型,因为该数组中还有其他类型的汽车。为了便于阅读,我在这里简化了它。
这就是我所做的:
let json = toJSON(arrayOfCars)
但由于某些原因,当转换为 JSON 时,SUVCar
的 weight
属性被忽略,即使 arrayOfCars
包含 SUVCar
个对象,我得到一个看起来像这样的 JSON:
[{brand: "MyBrand"}, {brand: "MyBrand"}]
那么如何在我的 JSON 中获取 SUVCar
的 weight
属性?我错过了什么?
谢谢。
class SUVCar: Car
{
enum SUVCarKeys: CodingKey {
case weight
}
var weight: Int
init(_ weight: Int)
{
self.weight = weight
super.init(brand: "MyBrand")
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: SUVCarKeys.self)
try container.encode(weight, forKey: .weight)
try super.encode(to: encoder)
}
}
如果您扩充子类的编码实现,那么您可以添加额外的属性
与其自定义所有子classes 以正确编码,不如引入一种可以容纳不同类型汽车的类型来解决这个问题
struct CarCollection: Encodable {
let suvs: [SUVCar]
let jeeps: [Jeep]
let sedans: [Sedan]
}
(假设另外两个sublclasses class Jeep: Car {}
和class Sedan: Car {}
)
那么你就不需要额外的代码,编码也很简单
let cars = CarCollection(suvs: [SUVCar(brand: "x", weight: 1000)],
jeeps: [Jeep(brand: "y")],
sedans: [Sedan(brand: "z")])
if let json = toJSON(cars) {
print(json)
}
{"jeeps":[{"brand":"x"}],"suvs":[{"brand":"x"}],"sedans":[{"brand":"a"}]}
有点跑题了,但是 struct 可能是比 class 更好的选择,或者至少它是推荐的选择,所以这里是使用 struct 和协议而不是 superclass。上面的代码仍然是一样的。
protocol Car : Encodable {
var brand: String { get set }
}
struct SUVCar : Car {
var brand: String
var weight: Int
}
struct Jeep: Car {
var brand: String
}
struct Sedan: Car {
var brand: String
}