1

在我的 iOS Swift 项目中,我需要将对象转换为 JSON。

我有一个简单的课程:

class Car : Encodable
{
    var brand: String

    init(brand: String)
    {
        self.brand = brand
    }
}

和一个子类:

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 时,即使包含对象,weight属性也会被忽略,我得到一个如下所示的 JSON:SUVCararrayOfCarsSUVCar

[{brand: "MyBrand"}, {brand: "MyBrand"}]

那么如何在我的 JSON 中获取 的weight属性?SUVCar我错过了什么?

谢谢。

4

2 回答 2

3
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)
    }
}

如果您增加子类的 encode 实现,那么您可以添加其他属性

于 2021-04-07T14:22:40.487 回答
1

您可以通过引入一种容纳不同类型汽车的类型来解决此问题,而不是自定义所有子类以正确编码

struct CarCollection: Encodable {
    let suvs: [SUVCar]
    let jeeps: [Jeep]
    let sedans: [Sedan]
}

(假设另外两个子类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 和协议而不是超类的外观。上面的代码仍然是相同的。

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
}
于 2021-04-07T15:29:43.560 回答