如何解决解码基于编码值 Swift 的类
我正在尝试根据编码数据的内容对特定类进行解码。
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,\"number_of_wheels\": 4},{\"kind\": 1,\"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]
如果可能的话。
解决方法
这是不使用 import React from "react";
import app from "../images/app.png";
const Featured = () => {
return (
<div className="mt-52 ">
<h1 className="text-primary-dark-theme text-5xl mt-14">Projects</h1>
<div className="grid grid-cols-12 grid-rows-1 mt-20 ">
<div className="row-start-1 row-span-1 col-start-1 md:col-span-6">
<img src={app} alt="" className="w-full" />
</div>
<div className="row-start-1 row-span-1 col-start-6 col-span-7">
<div className="h-full w-full">
<h1 className="text-right text-primary-dark-theme">
Featured Project
</h1>
<h1 className="text-right text-gray-300 font-bold ">Title</h1>
<p className="p-5 bg-gray-800 text-gray-400 shadow-lg rounded-md mt-5">
Lorem ipsum dolor sit,amet consectetur adipisicing elit. Optio id
doloribus sequi repellendus aperiam dolore!
</p>
</div>
</div>
</div>
</div>
);
};
export default Featured;
的替代解决方案。我也做了一些改变并引入了一个协议而不是一个超类。
Codable
不是很重要,但我将类型从 class 更改为 struct
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
}
进行解码,然后使用Vehicle
创建对象,分两步将json转换为JSONSerialization
数组
reduce(into:)
以上代码输出:
福特,轮子:4,类型:汽车
雅马哈,轮子:2,类型:摩托车
更新。可编码版本
通过引入一个单独的类型用于解码,我也设法提出了一个 Codable 解决方案。设置和之前一样,有一个协议和两个结构体。
然后我介绍了一种用于解码的特定类型(但它当然也可以扩展用于编码),它实现了自定义 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)
}
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)
}
}
}
,
您没有在类中定义 kind 属性。 另外,Car和Motorcycle没有区别 我在操场上对此进行了测试,似乎可以满足您的要求。
class Vehicle: Codable {
enum Kind: Int,Codable {
case car = 0,motorcycle = 1
}
let kind: Kind
let brand: String
let numberOfWheels: Int
}
class Car: Vehicle {}
class MotorCycle: 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)
//But what if I want to decode an array of vehicles,but have them decoded as a specific type?
let combined = "[{\"kind\": 0,\"number_of_wheels\": 4},{\"kind\": 1,\"number_of_wheels\": 2}]".data(using: .utf8)!
// Outputs [Project.Vehicle,Project.Vehicle]
let allVeh = try! decoder.decode([Vehicle].self,from: combined)
for veh in allVeh where veh.kind == Vehicle.Kind.motorcycle { // } is MotorCycle {
print(veh.brand,type(of: veh))
}
它给出: 雅马哈汽车
你也可以写
let allMotorcycles = allVeh.filter {$0.kind == Vehicle.Kind.motorcycle}
for moto in allMotorcycles {
print(moto.brand,type(of: moto))
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。