使用Codable使用同一密钥解码不同的类 [英] Using Codable to decode different classes using the same key
问题描述
我正在使用提供2个JSON URL的API。每个URL包含一个嵌套的容器,该容器具有属于同一类和对象的不同属性。
I'm working with an API that provides 2 JSON URLS. Each URL contains a nested container with different attributes that belong to the same class and object.
JSON URL 1
{
"last_updated": 1535936629,
"xyz": 5,
"data": {
"dataList": [
{
"id": "42",
"a1": "a1value",
"a2": "a2value",
},
// ,,,
]
}
}
JSON URL 2
{
"last_updated": 1536639996,
"xyz": 5,
"data": {
"dataList": [
{
"id": "42",
"a3": "a3value",
"a4": "a4value",
},
// ,,,
]
}
}
我想使用这些JSON URL来使用嵌套的 dataList
列表,所以我创建了一个 Feed
结构来处理这2个JSON文件。
I want to use these JSON URLS to create a single Codable CustomClass object using the items in the nested dataList
list, so I created a Feed
struct to handle these 2 JSON files.
Feed.swift
import Foundation
Struct Feed: Decodable {
var lastUpdated: Int
var xyz: Int
var data: KeyedDecodingContainer<Feed.dataCodingKey>
var dataList: [CustomClass]
enum CodingKeys: String, CodingKey {
case lastUpdated = "last_updated"
case xyz
case data
}
enum dataCodingKey: String, CodingKey {
case dataList
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.lastUpdated = try decoder.decode(Int.self, forKey: .lastUpdated)
self.xyz = try container.decode(Int.self, forKey: .xyz)
self.data = try container.nestedContainer(keyedBy: dataCodingKey.self, forKey: .data)
self.dataList = try data.decode([CustomClass].self, forKey: .dataList)
}
}
CustomClass.swift
class CustomClass: Decodable {
var id: String
var a1: String
var a2: Double
var a3: String
var a4: String
enum CodingKeys: String, CodingKey {
case id
case a1
case a2
case a3
case a4
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.id = try values.decode(String.self, forKey: .id)
self.a1 = try values.decode(String.self, forKey: .a1)
self.a2 = try values.decode(String.self, forKey: .a2)
self.a3 = try values.decode(String.self, forKey: .a3)
self.a4 = try values.decode(String.self, forKey: .a4)
}
}
在ViewController中,我执行了两个单独的异步调用来获取数据:
In my ViewController, I do two separate asynchronous calls to obtain the data:
ViewController.swift
var listOfCustomClass: [CustomClass]
var listOfCustomClass2: [CustomClass]
func getFeed(urlString: String, completionHandler: @escaping (_ result: Feed?) -> Void) {
// parses JSON to return a Feed object
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
}
guard let data = data else { return }
//Implement JSON decoding and parsing
do {
let feed = try JSONDecoder().decode(Feed.self, from: data)
DispatchQueue.main.async {
completionHandler(feed)
}
} catch {
print(error)
}
}.resume()
}
getFeed(urlString: url1String) { result in
// Obtain the contents of dataList from URL1
if let feed = result {
self.listOfCustomClass = feed.dataList
self.getFeed(urlString: url2String) { result in
//Upon completion, obtain the dataList info and populate the "a3" and "a4" attributes from CustomClass
if let feed = result {
let dataList2: [CustomClass] = feed.dataList
// code to merge self.listOfCustomClass 1 and self.listOfCustomClass2 into a single [CustomClass] list with all attributes and store it as self.listOfCustomClass
// Upon completion, return the finalized station array for use
DispatchQueue.main.async {
completionHandler(self.listOfCustomClass)
}
}
}
}
}
我遇到的问题是 dataList
CodingKey具有不同的键 a1
或 a2
(如果来自URL1或 a3
, a4
(如果来自URL2)。因此,只要在 dataList
容器中找不到4个键中的2个键,Codable init方法就会抱怨。
The problem I'm running into is that the dataList
CodingKey has different keys a1
or a2
if coming from URL1 or a3
, a4
if coming from URL2. Therefore the Codable init method is complaining whenever it can't find 2 of 4 keys in the dataList
container.
如何使用单个解码器实例化用a1,a2,a3和a4创建一个CustomClass对象?
How can I approach creating one CustomClass object with a1, a2, a3, and a4 instantiated using a single Decoder?
推荐答案
如果JSON到 CustomClass
可能包含或可能包含或不包含键 a1
, a2
等,那么它们必须是可选的……
If the JSON to CustomClass
may or may or may not contain keys a1
, a2
, etc, then they must be optional…
let a1: String?
let a2: Double?
let a3: String?
let a4: String?
然后只是使用情况
a1 = try values.decodeIfPresent(String.self, forKey: .a1)
这篇关于使用Codable使用同一密钥解码不同的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!