gpt4 book ai didi

json - 基于编码值Swift解码类

转载 作者:行者123 更新时间:2023-12-04 08:20:29 29 4
gpt4 key购买 nike

我正在尝试根据编码数据的内容解码特定的类。

class Vehicle: Codable {
enum Kind: Int, Codable {
case car = 0, motorcycle = 1
}

let brand: String
let numberOfWheels: Int
}

class Car: Vehicle {}
class MotorCycle: Vehicle {}
如您所见,我有一个通用的 Vehicle用于对车辆进行编码和解码的类型。这适用于如下所示的基本解码。
let car = "{\"kind\": 0, \"brand\": \"Ford\", \"number_of_wheels\": 4}".data(using: .utf8)!
let motorCycle = "{\"kind\": 1, \"brand\": \"Yamaha\", \"number_of_wheels\": 2}".data(using: .utf8)!

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

// Outputs a Project.Car
let ford = try! decoder.decode(Car.self, from: car)
// Outputs a Project.MotorCycle
let yamaha = try! decoder.decode(MotorCycle.self, from: motorCycle)
但是,如果我想解码一系列车辆,但将它们解码为特定类型怎么办?
let combined = "[{\"kind\": 0, \"brand\": \"Ford\", \"number_of_wheels\": 4}, {\"kind\": 1, \"brand\": \"Yamaha\", \"number_of_wheels\": 2}]".data(using: .utf8)!

// Outputs [Project.Vehicle, Project.Vehicle]
print(try! decoder.decode([Vehicle].self, from: combined))
如何使用 JSON 数据中的 kind 属性让解码器输出一系列车辆,但输入车辆。根据示例 [Project.Car, Project.MotorCycle]如果可能的话。

最佳答案

这是不使用 Codable 的替代解决方案.我还做了一些更改并引入了协议(protocol)而不是父类(super class)。

protocol Vehicle: CustomStringConvertible {
var brand: String { get set }
var numberOfWheels: Int { get set }
}

extension Vehicle {
var description: String {
"\(brand), wheels: \(numberOfWheels), type: \(type(of:self))"
}
}
不是那么重要,但我将类型从类更改为结构
struct Car: Vehicle {
var brand: String
var numberOfWheels: Int
}

struct MotorCycle: Vehicle {
var brand: String
var numberOfWheels: Int
}
然后将 json 转换为 Vehicle使用 JSONSerialization 分两步排列数组用于解码,然后 reduce(into:)创建对象
do {
if let array = try JSONSerialization.jsonObject(with: combined) as? [[String: Any]] {
let vehicles = array.reduce(into: [Vehicle]()) {
if let kindValue = $1["kind"] as? Int,
let kind = VehicleKind(rawValue: kindValue),
let brand = $1["brand"] as? String,
let numberOfWheels = $1["number_of_wheels"] as? Int {
switch kind {
case .car:
$0.append(Car(brand: brand, numberOfWheels: numberOfWheels))
case .motorcycle:
$0.append(MotorCycle(brand: brand, numberOfWheels: numberOfWheels))
}
}
}
for vehicle in vehicles {
print(vehicle)
}
}
} catch {
print(error)
}
上面的代码输出:

Ford, wheels: 4, type: Car
Yamaha, wheels: 2, type: MotorCycle



更新。可编码版本
通过引入一个单独的类型用于解码,我设法提出了一个 Codable 解决方案。设置与以前相同,带有一个协议(protocol)和两个结构。
然后我介绍了一个特定的解码类型(当然它也可以扩展为编码),它实现了自定义 init(from:)
struct JsonVehicle: Decodable {
let vehicle: Vehicle

enum CodingKeys: String, CodingKey {
case kind
case brand
case numberOfWheels
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

let kind = try container.decode(VehicleKind.self, forKey: .kind)
let brand = try container.decode(String.self, forKey: .brand)
let wheels = try container.decode(Int.self, forKey: .numberOfWheels)
switch kind {
case .car:
vehicle = Car(brand: brand, numberOfWheels: wheels)
case .motorcycle:
vehicle = MotorCycle(brand: brand, numberOfWheels: wheels)
}
}
}
最终结果再次通过 2 个步骤实现
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

let result = try decoder.decode([JsonVehicle].self, from: combined)
let vehicles = result.map(\.vehicle)
} catch {
print(error)
}

关于json - 基于编码值Swift解码类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65521457/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com