我想对同一个项目的两个具有不同字段的JSON URL进行解码,然后使用结构或类将它们组合成一个模型对象。我能够使用一个JSON URL并根据需要对其进行解码,但是在添加第二个URL时却很费力。我目前一直在使用结构,但是我将处理大量数据,因此我知道在这里使用类会更好。任何其他建议将不胜感激。我已经搜索了很多,但是无法迅速找到与这种情况相关的信息。
下面有一个示例,希望可以对其进行操作以执行我要尝试执行的操作。在这里,我们有1个提供状态,缩写和区域成员的端点。另一个端点提供州,人口和面积。
class CollectionViewController: UIViewController {
let urlStates1 = "https://......endpoint1"
let urlStates2 = "https://......endpoint2"
var states = [StatesData]()
override func viewDidLoad() {
super.viewDidLoad()
downloadJSON() {
self.CollectionView.reloadData()
}
}
func downloadJSON(completed:@escaping ()->()){
let url1 = URL(string: urlStates1)
URLSession.shared.dataTask(with: url1!) { (data, response, error) in
if error == nil {
do{
self.states = try JSONDecoder().decode([StatesData].self, from: data!)
DispatchQueue.main.async{
completed()
}
} catch {
print("JSON Error")
}}
}.resume()
}
这是我的结构
struct StatesData : Decodable {
//////Members from URL1///////
var state : String?
var abrev : String?
var region : String?
//////Members specific to URL2///////
var population : Int?
var area : Double?
private enum AttributeKeys: String, CodingKey {
case state = "state"
case abrev = "abrev"
case region = "region"
}
private enum StatisticsKeys: String, CodingKey {
case state = "state"
case population = "population"
case area = "area"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: AttributeKeys.self)
if let stateName = try values.decodeIfPresent(String.self, forKey: .state) {
state = stateName
abrev = try values.decodeIfPresent(String.self, forKey: .abrev)!
region = try values.decodeIfPresent(String.self, forKey: .region)!
} else {
let values = try decoder.container(keyedBy: StatisticsKeys.self)
state = try values.decodeIfPresent(String.self, forKey: .state)!
population = try values.decodeIfPresent(Int.self, forKey: .population)!
area = try values.decodeIfPresent(Double.self, forKey: .area)!
}
}
}
}
让我们说urlStates1的JSON响应如下
[
{
"state": "Connecticut",
"abrev": "CT",
"region": "Northeast"
},
{
"state": "Texas",
"abrev": "TX",
"region": "Southwest"
}
]
并且urlStates2的JSON响应如下
[
{
"state": "Connecticut",
"population": 3588000,
"area": 5543.00
},
{
"state": "Texas",
"population": 28300000,
"area": 268597.00
}
]
答案 0 :(得分:0)
在当前的实现中,您的StatesData
结构中存在两个问题。
1)属性类型与响应中的值类型(即人口和面积)不匹配。
2)您的if语句在解码器中始终为true,因为这两种响应都存在key .state,因此它绝不会解码第二种类型的响应。
请查看更正后的StatesData
,现在您应该能够正确解码响应了。
struct StatesData : Decodable {
//////Members from URL1///////
var state : String?
var abrev : String?
var region : String?
//////Members specific to URL2///////
var population : String?
var area : String?
private enum AttributeKeys: String, CodingKey {
case state = "state"
case abrev = "abrev"
case region = "region"
}
private enum StatisticsKeys: String, CodingKey {
case state = "state"
case population = "population"
case area = "area"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: AttributeKeys.self)
if let abrevName = try values.decodeIfPresent(String.self, forKey: .abrev) {
state = try values.decodeIfPresent(String.self, forKey: .state)
abrev = abrevName
region = try values.decodeIfPresent(String.self, forKey: .region)
} else {
let values = try decoder.container(keyedBy: StatisticsKeys.self)
state = try values.decodeIfPresent(String.self, forKey: .state)
population = try values.decodeIfPresent(String.self, forKey: .population)
area = try values.decodeIfPresent(String.self, forKey: .area)
}
}
}