如何将 Alamofire 与 Codable 协议一起使用并解析数据
How to use Alamofire with Codable protocol and parse data
第一次用Codable协议,很多东西不太清楚。在阅读了几个教程之后,开始使用 Codable 来解析数据。下面是代码:
struct MyTasks : Codable {
var strDateDay : String = ""
var strReminder : String = ""
var strRepetitions : String = ""
var name : String = ""
var strNotes : String = ""
var strUserId : String = ""
private enum CodingKeys: String, CodingKey {
case strDateDay = "duedate"
case strReminder = "reminder"
case strRepetitions = "recurring"
case name = "name"
case strNotes = "notes"
case strUserId = "userId"
}
}
let networkManager = DataManager()
networkManager.postLogin(urlString: kGetMyTasks, header: header, jsonString: parameters as [String : AnyObject]) { (getMyTasks) in
print(getMyTasks?.name as Any) // -> for log
Common_Methods.hideHUD(view: self.view)
}
// 网络管理员:
func postLogin(urlString: String, header: HTTPHeaders, jsonString:[String: AnyObject], completion: @escaping (MyTasks?) -> Void) {
let apiString = KbaseURl + (kGetMyTasks as String)
print(apiString)
Alamofire.request(apiString, method: .post, parameters: jsonString , encoding: URLEncoding.default, headers:header).responseJSON
{ response in
let topVC = UIApplication.shared.keyWindow?.rootViewController
DispatchQueue.main.async {
//Common_Methods.showHUD(view: (topVC?.view)!)
}
guard let data = response.data else { return }
do {
let decoder = JSONDecoder()
let loginRequest = try decoder.decode(MyTasks.self, from: data)
completion(loginRequest)
} catch let error {
print(error)
completion(nil)
}
}
}
现在,这是回复:
keyNotFound(CodingKeys(stringValue: "strDateDay", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"strDateDay\", intValue: nil) (\"strDateDay\").", underlyingError: nil))
下面是我试图解析的 json 响应:
{
"data": [
{
"userId": 126,
"name": "My task from postman ",
"notes": null,
"totalSteps": 0,
"completedSteps": 0,
"files": 0
},
{
"userId": 126,
"name": "My task from postman 1",
"notes": null,
"totalSteps": 0,
"completedSteps": 0,
"files": 0
}
]
}
我知道我遗漏了一些东西,但即使花了半天多的时间,我也没有正确理解哪里出了问题。请指导。
问题出在你的结构上,结构中属性的名称应该与 json 数据匹配,或者如果你想使用自定义名称,你应该使用 enum CodingKeys
将它们转换为你喜欢的
struct MyTasks: Codable {
let data: [Datum]
}
struct Datum: Codable {
let userID: Int?
let name: String
let notes: String?
let totalSteps, completedSteps, files: Int
enum CodingKeys: String, CodingKey {
case userID = "userId"
case name, notes, totalSteps, completedSteps, files
}
}
func postLogin(urlString: String, header: HTTPHeaders, jsonString:[String: AnyObject], completion: @escaping (MyTasks?) -> Void) {
let apiString = KbaseURl + (kGetMyTasks as String)
print(apiString)
Alamofire.request(apiString, method: .post, parameters: jsonString , encoding: URLEncoding.default, headers:header).responseJSON
{ response in
let topVC = UIApplication.shared.keyWindow?.rootViewController
DispatchQueue.main.async {
//Common_Methods.showHUD(view: (topVC?.view)!)
}
guard let data = response.data else { return }
do {
let decoder = JSONDecoder()
let loginRequest = try decoder.decode(MyTasks.self, from: data)
completion(loginRequest)
} catch let error {
print(error)
completion(nil)
}
}
}
还有一件事要记住,你知道 notes
的确切类型并使其成为可选的,否则会出现错误,没有类型所以我在那里放了一个可选的字符串。
希望这会有所帮助。
问题是在你的顶部 JSON 你有一个 "data" 属性 类型 array
.
您要求 JSON解码器将仅包含 "data" 属性 的 JSON 对象解码为名为 "MyTasks" 的 Swift 对象您定义的存储属性(包括 strDateDay)。
因此解码器向您发送此响应是因为他无法在该顶部对象中找到 strDateDay。
您必须创建一个顶级对象以进行反序列化。像 :
struct MyResponse: Codable {
var data: [MyTasks]
}
然后就像您已经完成的那样将它提供给您的JSON解码器:
let loginRequest = try decoder.decode(MyResponse.self, from: data)
您发送给解码器的数据是您的完整 JSON 流(Alamofire 响应对象的数据 属性),而不仅仅是 "data" 属性你的 JSON 结构。
我建议使用 CodyFire lib 因为它支持与请求相关的所有 Codable。
您的 POST 请求可能看起来像
struct MyTasksPayload: JSONPayload {
let param1: String
let param2: String
}
struct MyTasksResponseModel: Codable {
let strDateDay: String
let strReminder: String
let strRepetitions: String
let name: String
}
let server = ServerURL(base: "https://server1.com", path: "v1")
APIRequest<[MyTasksResponseModel]>(server, "mytasks", payload: payloadModel)
.method(.post)
.onRequestStarted {
// show HUD here
}
.onError {
// hide hud and show error here
}
.onSuccess { tasks in
// here's your decoded tasks
// hide hud here
}
使用APIRequest<[MyTasksResponseModel]>
解码数组
使用APIRequest解码一个对象
第一次用Codable协议,很多东西不太清楚。在阅读了几个教程之后,开始使用 Codable 来解析数据。下面是代码:
struct MyTasks : Codable {
var strDateDay : String = ""
var strReminder : String = ""
var strRepetitions : String = ""
var name : String = ""
var strNotes : String = ""
var strUserId : String = ""
private enum CodingKeys: String, CodingKey {
case strDateDay = "duedate"
case strReminder = "reminder"
case strRepetitions = "recurring"
case name = "name"
case strNotes = "notes"
case strUserId = "userId"
}
}
let networkManager = DataManager()
networkManager.postLogin(urlString: kGetMyTasks, header: header, jsonString: parameters as [String : AnyObject]) { (getMyTasks) in
print(getMyTasks?.name as Any) // -> for log
Common_Methods.hideHUD(view: self.view)
}
// 网络管理员:
func postLogin(urlString: String, header: HTTPHeaders, jsonString:[String: AnyObject], completion: @escaping (MyTasks?) -> Void) {
let apiString = KbaseURl + (kGetMyTasks as String)
print(apiString)
Alamofire.request(apiString, method: .post, parameters: jsonString , encoding: URLEncoding.default, headers:header).responseJSON
{ response in
let topVC = UIApplication.shared.keyWindow?.rootViewController
DispatchQueue.main.async {
//Common_Methods.showHUD(view: (topVC?.view)!)
}
guard let data = response.data else { return }
do {
let decoder = JSONDecoder()
let loginRequest = try decoder.decode(MyTasks.self, from: data)
completion(loginRequest)
} catch let error {
print(error)
completion(nil)
}
}
}
现在,这是回复:
keyNotFound(CodingKeys(stringValue: "strDateDay", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"strDateDay\", intValue: nil) (\"strDateDay\").", underlyingError: nil))
下面是我试图解析的 json 响应:
{
"data": [
{
"userId": 126,
"name": "My task from postman ",
"notes": null,
"totalSteps": 0,
"completedSteps": 0,
"files": 0
},
{
"userId": 126,
"name": "My task from postman 1",
"notes": null,
"totalSteps": 0,
"completedSteps": 0,
"files": 0
}
]
}
我知道我遗漏了一些东西,但即使花了半天多的时间,我也没有正确理解哪里出了问题。请指导。
问题出在你的结构上,结构中属性的名称应该与 json 数据匹配,或者如果你想使用自定义名称,你应该使用 enum CodingKeys
将它们转换为你喜欢的
struct MyTasks: Codable {
let data: [Datum]
}
struct Datum: Codable {
let userID: Int?
let name: String
let notes: String?
let totalSteps, completedSteps, files: Int
enum CodingKeys: String, CodingKey {
case userID = "userId"
case name, notes, totalSteps, completedSteps, files
}
}
func postLogin(urlString: String, header: HTTPHeaders, jsonString:[String: AnyObject], completion: @escaping (MyTasks?) -> Void) {
let apiString = KbaseURl + (kGetMyTasks as String)
print(apiString)
Alamofire.request(apiString, method: .post, parameters: jsonString , encoding: URLEncoding.default, headers:header).responseJSON
{ response in
let topVC = UIApplication.shared.keyWindow?.rootViewController
DispatchQueue.main.async {
//Common_Methods.showHUD(view: (topVC?.view)!)
}
guard let data = response.data else { return }
do {
let decoder = JSONDecoder()
let loginRequest = try decoder.decode(MyTasks.self, from: data)
completion(loginRequest)
} catch let error {
print(error)
completion(nil)
}
}
}
还有一件事要记住,你知道 notes
的确切类型并使其成为可选的,否则会出现错误,没有类型所以我在那里放了一个可选的字符串。
希望这会有所帮助。
问题是在你的顶部 JSON 你有一个 "data" 属性 类型 array
.
您要求 JSON解码器将仅包含 "data" 属性 的 JSON 对象解码为名为 "MyTasks" 的 Swift 对象您定义的存储属性(包括 strDateDay)。
因此解码器向您发送此响应是因为他无法在该顶部对象中找到 strDateDay。
您必须创建一个顶级对象以进行反序列化。像 :
struct MyResponse: Codable {
var data: [MyTasks]
}
然后就像您已经完成的那样将它提供给您的JSON解码器:
let loginRequest = try decoder.decode(MyResponse.self, from: data)
您发送给解码器的数据是您的完整 JSON 流(Alamofire 响应对象的数据 属性),而不仅仅是 "data" 属性你的 JSON 结构。
我建议使用 CodyFire lib 因为它支持与请求相关的所有 Codable。
您的 POST 请求可能看起来像
struct MyTasksPayload: JSONPayload {
let param1: String
let param2: String
}
struct MyTasksResponseModel: Codable {
let strDateDay: String
let strReminder: String
let strRepetitions: String
let name: String
}
let server = ServerURL(base: "https://server1.com", path: "v1")
APIRequest<[MyTasksResponseModel]>(server, "mytasks", payload: payloadModel)
.method(.post)
.onRequestStarted {
// show HUD here
}
.onError {
// hide hud and show error here
}
.onSuccess { tasks in
// here's your decoded tasks
// hide hud here
}
使用APIRequest<[MyTasksResponseModel]>
解码数组
使用APIRequest解码一个对象