我正在使用向我提供Json的API,如下所示
{
"data": [
{
"title": "Banners",
"type": "banners",
"sequence": 1,
"is_enabled": 1,
"categories": [
{
"title": "banner-01",
"image": "http://design.example.com/b2c/assets/banners/banner-01.png?v=1",
"method": "onPressBanner",
"url": "https://example.ng/download",
"description": null
}
]
},
{
"title": "Current Orders",
"type": "orders",
"sequence": 4,
"is_enabled": 1,
"categories": [
{
"customer_id": 26042,
"customer": "XYZ",
"order_id": 2071,
"order_status_id": 9,
"status": "complete",
"order_type": "product",
"product_id": 2075,
"product_name": "Cholesterol Regulator",
"total_amount": 10750,
"is_payment_received": 1,
"paymentMethod": "pos",
"payable_amount": 10750,
"added_on": "2018-11-27T01:45:09.000Z"
}
]
}
]
}
现在的问题是,我在 categories 键中获得了不同类型的对象数组,因此我试图通过使 categories 泛型来解决此问题。 类型为 DataList
我的可降解类如下
struct DataList<T : Decodable> : Decodable {
let dataList: [T]
}
这是我的外部对象 Dashboard 类的结构
struct DashBoard<T : Decodable> : Decodable {
let title: String?
let type: String?
let sequence: Int?
let is_enabled: Int?
let categories : DataList<T>?
var cellType: DashBoardSectionType?
enum CodingKeys: String, CodingKey {
case title = "title"
case type = "type"
case categories = "categories"
case sequence = "sequence"
case is_enabled = "is_enabled"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
title = try values.decodeIfPresent(String.self, forKey: .title)
type = try values.decodeIfPresent(String.self, forKey: .type)
is_enabled = try values.decodeIfPresent(Int.self, forKey: .is_enabled)
sequence = try values.decodeIfPresent(Int.self, forKey: .sequence)
cellType = DashBoardSectionType(rawValue: type!) ?? .OTHER
if cellType == .ORDERS {
categories = try (values.decodeIfPresent(DataList<Order>.self, forKey: .categories) as? DataList<T>)
}else{
categories = try (values.decodeIfPresent(DataList<Category>.self, forKey: .categories) as? DataList<T>)
}
}
}
然后是类别内单独对象的单独结构,一个是订单,另一个是类别
订购
struct Order: Codable {
let customerID: Int
let customer: String
let orderID, orderStatusID: Int
let status, orderType: String
let productID: Int
let productName: String
let totalAmount, isPaymentReceived: Int
let paymentMethod: String
let payableAmount: Int
let addedOn: String
enum CodingKeys: String, CodingKey {
case customerID = "customer_id"
case customer
case orderID = "order_id"
case orderStatusID = "order_status_id"
case status
case orderType = "order_type"
case productID = "product_id"
case productName = "product_name"
case totalAmount = "total_amount"
case isPaymentReceived = "is_payment_received"
case paymentMethod
case payableAmount = "payable_amount"
case addedOn = "added_on"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
orderID = try values.decodeIfPresent(Int.self, forKey: .orderID) ?? 0
customer = try values.decodeIfPresent(String.self, forKey: .customer) ?? ""
customerID = try values.decodeIfPresent(Int.self, forKey: .customerID) ?? 0
status = try values.decodeIfPresent(String.self, forKey: .status) ?? ""
orderStatusID = try values.decodeIfPresent(Int.self, forKey: .orderStatusID) ?? 0
payableAmount = try values.decodeIfPresent(Int.self, forKey: .payableAmount) ?? 0
addedOn = try values.decodeIfPresent(String.self, forKey: .addedOn) ?? ""
orderType = try values.decodeIfPresent(String.self, forKey: .orderType) ?? ""
productID = try values.decodeIfPresent(Int.self, forKey: .productID) ?? 0
productName = try values.decodeIfPresent(String.self, forKey: .productName) ?? ""
isPaymentReceived = try values.decodeIfPresent(Int.self, forKey: .isPaymentReceived) ?? 0
totalAmount = try values.decodeIfPresent(Int.self, forKey: .productName) ?? 0
paymentMethod = try values.decodeIfPresent(String.self, forKey: .paymentMethod) ?? ""
}
}
类别
struct Category: Decodable {
let title : String?
let image : String?
let method : String?
let url : String?
let description: String?
enum CodingKeys: String, CodingKey {
case title = "title"
case image = "image"
case method = "method"
case url = "url"
case description
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
title = try values.decodeIfPresent(String.self, forKey: .title)
image = try values.decodeIfPresent(String.self, forKey: .image)
method = try values.decodeIfPresent(String.self, forKey: .method)
url = try values.decodeIfPresent(String.self, forKey: .url)
description = try values.decodeIfPresent(String.self, forKey: .description)
}
}
let decoder = JSONDecoder()
let dashBoardArr = try decoder.decode([DashBoard].self, from: data)
基本上Xcode要求我为Decodable的通用类型指定类型
请提出如何解决这个问题
答案 0 :(得分:1)
您可以创建另一种类型来保留Orders
或Categories
,并使用type
来从响应中解析出哪一个类型。请参见下面的实现,以针对相同的键(即categories
)处理两种类型。
struct DataList: Decodable {
let data: [DashBoard]
}
enum OrderOrCategoryType {
case unknown, order, category
}
struct OrderOrCategory {
var order: [Order]?
var categories: [Category]?
}
struct DashBoard: Decodable {
let title: String?
let type: String?
let sequence: Int?
let is_enabled: Int?
let categories: OrderOrCategory?
var categoryType: OrderOrCategoryType = .unknown
enum CodingKeys: String, CodingKey {
case title = "title"
case type = "type"
case categories = "categories"
case sequence = "sequence"
case is_enabled = "is_enabled"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
title = try values.decodeIfPresent(String.self, forKey: .title)
type = try values.decodeIfPresent(String.self, forKey: .type)
is_enabled = try values.decodeIfPresent(Int.self, forKey: .is_enabled)
sequence = try values.decodeIfPresent(Int.self, forKey: .sequence)
if let orders = try? values.decodeIfPresent([Order].self, forKey: .categories) {
self.categories = OrderOrCategory(order: orders, categories: nil)
categoryType = .order
} else {
categoryType = .category
let categories = try values.decodeIfPresent([Category].self, forKey: .categories)
self.categories = OrderOrCategory(order: nil, categories: categories)
}
}
}
现在您可以将其解析为这样,
let dataList = try decoder.decode(DataList.self, from: data)