如何在Swift中使用Decodable?

7

我将在我的项目中使用一个免费的日期API。我将使用Decodable解析JSON数据。

这里我创建了我的struct

struct jsonStruct: Decodable {
var message: Bool?
var data: [dateData]
}

struct dateData: Decodable {
var quarter: Int?
var day: String?
var month: String?
}

这是我使用解码器的代码:-
let jsonUrlString = "https://api.lrs.org/random-date-generator?lim_quarters=40&source=api-docs"
guard let url = URL(string: jsonUrlString) else { return }
    
URLSession.shared.dataTask(with: url) { (data, reponse, err) in
    guard let data = data  else { return }
    print(data)
        
    do {
        let jsonData = try JSONDecoder().decode([dateData].self, from: data)
        print(jsonData)
    }
    catch let jsonerr {
        print("error serrializing error",jsonerr)
    }
}.resume()

但是我的代码出现了错误。它只会进入catch块,我在控制台中得到了以下错误:

error serrializing error typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))

我不明白我代码里做错了什么。

API数据:

{
messages: false,
data: {
2018-01-02: {
quarter: 1,
day: "2",
month: "1",
db: "2018-01-02",
long: "Tuesday, January 2nd, 2018",
unix: 1514876400
},

可能是JSON解码器类型不匹配错误的重复问题。 - Nilanshu Jaiswal
你能展示一下API的原始响应吗?看起来你期望JSON负载不带键包含一个对象数组,但实际负载是不同的。 - Losiowaty
@Losiowaty... 我修改了我的问题,请检查。 - Nilu Sahani
请学会阅读JSON。这很容易。只有两种集合类型,数组([])和字典({})。字典变成了结构体/类。正如您所看到的,根本没有数组。 - vadian
2个回答

12

你需要

struct Root: Codable {
    let messages: Bool
    let data: [String: Datum]
}

struct Datum: Codable {
    let quarter: Int
    let day, month, db, long: String
    let unix: Int
}


let jsonData = try JSONDecoder().decode(Root.self, from: data)
print(jsonData.data.values)

由于 JSON 的根是一个字典而不是数组,同时 data 也是一个字典。

jsonData.data.forEach {
  if $0 == " 2018-01-02" {
    print($1.month)
  }
}

但是先生,我如何使用“Decodable”来完成它?我想用它来做。 - Nilu Sahani
3
Codable是由DecodableEncodable组成的,它让你能够编码和解码,如果只需要解码,可以将其设置为Decodable - Shehata Gamal
它正在提供所有的值,但我想要一个特定的值,而我不知道该怎么做 :( - Nilu Sahani
我在控制台中看到了这个警告信息:warning: could not execute support code to read Objective-C class data in the process. This may reduce the quality of type information available. - Nilu Sahani
无法在进程中执行支持代码以读取Objective-C类数据。请确保你的APP和Xcode都使用相同的Swift版本,并尝试清除并重新构建您的项目。如果问题仍然存在,请检查您的构建设置是否正确。如果没有,请手动添加Objective-C桥接头文件。 - Shehata Gamal
还有一个问题,它给了我所有的字典值,如果我只想要月份值,我该怎么做? - Nilu Sahani

12
struct Job: Decodable {
   var title: String
   var salary: Float

  init(title: String, salary: Float) {
      self.title = title
      self.salary = salary
   }

   enum CodingKeys: String, CodingKey {
     case title, salary
   }
}

struct Person: Decodable {
   var job: Job
   var firstName: String
   var lastName: String
   var age: Int

     init(job: Job, firstName: String, lastName: String, age: Int) {
       self.job = job
       self.firstName = firstName
       self.lastName = lastName
       self.age = age
   }

   enum CodingKeys: String, CodingKey {
       case job = "job_information", firstName = "firstname", lastName = 
       "lastname", age
    }
}

let rawData = """
 {
    "job_information": {
      "title": "iOS Developer",
      "salary": 5000
   },
   "firstname": "John",
   "lastname": "Doe",
    "age": 20
}
 """.data(using: .utf8)!


let person = try JSONDecoder().decode(Person.self, from: rawData)
print(person.firstName) // John
print(person.lastName) // Doe
print(person.job.title) // iOS Developer

1
这是一个非常清晰易懂的例子。谢谢! - tjb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接