如何使用 jsonDecoder 处理来自 JSON 响应的动态键?



如何在 Swift 4 中使用解码器处理此 JSON 并解析此 JSON?我尝试了几次,但失败了。我不明白如何处理这种 JSON 格式。

[
{
products: {
id: 69,
name: "test",
des: "Hi this is a test",
sort_des: "this is a test category",
},
documents: {
0: {
id: 1,
name: "105gg_1992uu",
citation: "This is citation for 105gg_1992uu",
file: "105gg_1992uu.pdf",
created_at: "2019-01-25 09:07:09",
category_id: 69,
},
1: {
id: 2,
name: "96tt-1997tt",
citation: "This is citation for 96tt-1997tt",
file: "96tt-1997tt.pdf",
created_at: "2019-01-25 09:07:09",
category_id: 69,
},
},
}
]

我尝试了以下代码。 这是我的模型班。

struct GenericCodingKeys: CodingKey {
var stringValue: String
var intValue: Int?
init?(stringValue: String) {
self.stringValue = stringValue
}
init?(intValue: Int) {
self.intValue = intValue
self.stringValue = "(intValue)"
}
}
struct Model : Codable {
struct Documents : Codable {
var id : Int?
var name : String?
var citation : String?
var file : String?
var created_at : String?
var category_id : Int?## Heading ##
private enum CodingKeys : String, CodingKey{
case id = "id"
case name =  "name"
case citation = "citation"
case file = "file"
case created_at = "created_at"
case category_id = "category_id"
}
}
struct Products : Codable {
var id : Int?
var name : String?
var des : String?
var sort_des : String?
private enum CodingKeys: String, CodingKey{
case id = "id"
case name = "name"
case des = "des"
case sort_des = "sort_des"
}
}
var products : Products?
var documents : [Documents]?
private enum CodingKeys : String, CodingKey{
case products
case documents
}
init(from decoder: Decoder) throws {
self.documents = [Documents]()
let container = try decoder.container(keyedBy: CodingKeys.self)
self.products = try container.decode(Products.self, forKey: .products)
let documents = try container.nestedContainer(keyedBy: GenericCodingKeys.self, forKey: .documents)
for doc in documents.allKeys{
let docEach = try documents.decode(Documents.self, forKey: doc)
self.documents?.append(docEach)
}
}
}

这是我从该 JSON 函数中获取数据

class LatestStatuesVC: UIViewController,UITableViewDelegate,UITableViewDataSource {
@IBOutlet var tableView: UITableView!
var caseData : [Model]?
var model : Model?
var countCaseData = 0
override func viewDidLoad() {
super.viewDidLoad()
downloadAllData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return countCaseData
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: ReuseIdentifiers.cellLatestStatues, for: indexPath) as! LatestStatuesTableCell
return cell
}
//MARK: Download all documents into internal directory
func downloadAllData(){
let url = URL(string: URLString.urlForGetDocuments)
URLSession.shared.dataTask(with: url!) { (data, response, err) in
DispatchQueue.main.async {
do{
if err == nil {
let products = try JSONDecoder().decode(Model.Products.self, from: data!)
let documentAll = try JSONDecoder().decode([Model.Documents].self, from: data!)
print(products.name as Any)
self.countCaseData = documentAll.count
for doc in documentAll{
print(doc.name as Any)
print(doc.citation as Any)
}
}
}
catch let err{
print(err)
}
}
}.resume()
}
}

我收到此代码的错误。

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

该错误清楚地表明 JSON 的根对象是一个数组,但您尝试解码字典。

基本上你的结构太复杂了。如果你想通过摆脱数字字典键来documents数组,只需在根(Model)结构中编写一个自定义初始值设定项,该结构将documents解码为字典,并将按id排序的值作为documents数组。

struct Model : Decodable {
let products : Product
let documents : [Document]
enum CodingKeys: String, CodingKey { case products, documents }
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
products = try container.decode(Product.self, forKey: .products)
let documentData = try container.decode([String:Document].self, forKey: .documents)
documents = documentData.values.sorted(by: {$0.id < $1.id})
}
}
struct Product: Decodable {
let id : Int
let name, description, sortDescription : String
let type : String
}
struct Document: Decodable {
let id, categoryId : Int
let name, citation, file : String
let createdAt : Date
}

然后解码JSON(假设data将JSON表示为Data),createdAt值被解码为Date

let decoder = JSONDecoder()
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
decoder.dateDecodingStrategy = .formatted(dateFormatter)
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let modelArray = try decoder.decode([Model].self, from: data)
for model in modelArray {
print("products:",model.products)
print("documents:",model.documents)
}
} catch { print(error) }

convertFromSnakeCase键解码策略将所有snake_cased键转换为驼峰结构体成员,而不指定任何CodingKeys

相关内容

  • 没有找到相关文章

最新更新