【发布时间】:2019-02-19 20:56:16
【问题描述】:
我正在使用提供 2 个 JSON URL 的 API。每个 URL 都包含一个嵌套容器,该容器具有属于同一类和对象的不同属性。
JSON 网址 1
{
"last_updated": 1535936629,
"xyz": 5,
"data": {
"dataList": [
{
"id": "42",
"a1": "a1value",
"a2": "a2value",
},
// ,,,
]
}
}
JSON 网址 2
{
"last_updated": 1536639996,
"xyz": 5,
"data": {
"dataList": [
{
"id": "42",
"a3": "a3value",
"a4": "a4value",
},
// ,,,
]
}
}
我想使用这些 JSON URL 来使用嵌套的 dataList 列表中的项目创建单个 Codable CustomClass 对象,因此我创建了一个 Feed 结构来处理这 2 个 JSON 文件。
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 中,我执行了两个单独的异步调用来获取数据:
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。因此,只要 Codable init 方法在 dataList 容器中找不到 4 个键中的 2 个,它就会抱怨。
如何使用单个解码器实例化 a1、a2、a3 和 a4 创建一个 CustomClass 对象?
【问题讨论】:
-
这里根本不清楚你在问什么。请阅读minimal reproducible example,然后阅读edit 您的问题,其中显示了演示问题的最小代码
-
请给出一个实际不工作的代码示例。例如,如果您的类继承自
MKAnnotation,请在您的问题中表明这一点 - 但不要包含视图控制器中的所有代码 - 数据的下载方式不会影响数据的解码方式。 -
@AshleyMills 我已经编辑了我的问题以包含我在 cmets 中提供的增量信息,并在最后一句中澄清了问题。
-
在收到答案后更改您的问题是不合适的,因为这会使您收到的答案无效。它甚至会使这些答案出错,并对回答者的声誉产生不利影响。如果您现在有新问题或其他问题,请创建一个新帖子并在那里提问;如果需要参考,您可以链接回此链接。我已经回滚了你的问题以对应给出的答案。
-
@AshleyMills 显然我没有在这里做事。我从您之前的回复中得知,目前尚不清楚问题是什么,并且向 cmets 添加增量信息是不好的做法,并且您要求我编辑问题主体本身。我为来回道歉。目前我不确定如何正确接收反馈。