在iOS Swift中使用codable解析嵌套的json响应数据?
我试图用swift 4中的可解码格式解析json数据。它打印零值。我找不到这是什么问题 以下是模型类:在iOS Swift中使用codable解析嵌套的json响应数据?,json,swift,xcode,nested,codable,Json,Swift,Xcode,Nested,Codable,我试图用swift 4中的可解码格式解析json数据。它打印零值。我找不到这是什么问题 以下是模型类: public struct TaskID: Decodable { let embedded: Embedded? let count: Int? enum CodingKeys: String, CodingKey { case count = "count" case embedded = "_embedded" } } public struct Embedd
public struct TaskID: Decodable {
let embedded: Embedded?
let count: Int?
enum CodingKeys: String, CodingKey {
case count = "count"
case embedded = "_embedded"
}
}
public struct Embedded: Decodable {
let task: [Task]?
enum CodingKeys: String, CodingKey {
case task = "task"
}
}
public struct Task : Decodable {
let id : String?
let name: String?
let assignee: String?
let created: String?
let processDefinitionId: String?
enum CodingKeys: String, CodingKey {
case id = "id"
case name = "name"
case assignee = "assignee"
case created = "created"
case processDefinitionId = "processDefinitionId"
}
}
以下是json:
{
"_links": {
"self": {
"href": "/task"
}
},
"_embedded": {
"task": [
{
"_links": {
"assignee": {
"href": "/user/demo"
},
"execution": {
"href": "/execution/1b64cf75-0616-11ea-8860-120ef5ab2c25"
},
"identityLink": {
"href": "/task/1b64f688-0616-11ea-8860-120ef5ab2c25/identity-links"
},
"processDefinition": {
"href": "/process-definition/quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25"
},
"processInstance": {
"href": "/process-instance/1b64cf75-0616-11ea-8860-120ef5ab2c25"
},
"self": {
"href": "/task/1b64f688-0616-11ea-8860-120ef5ab2c25"
}
},
"_embedded": {
"variable": []
},
"id": "1b64f688-0616-11ea-8860-120ef5ab2c25",
"name": "Quick Evaluation",
"assignee": "demo",
"created": "2019-11-13T13:04:20.687+0000",
"due": null,
"followUp": null,
"delegationState": null,
"description": null,
"executionId": "1b64cf75-0616-11ea-8860-120ef5ab2c25",
"owner": null,
"parentTaskId": null,
"priority": 50,
"processDefinitionId": "quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25",
"processInstanceId": "1b64cf75-0616-11ea-8860-120ef5ab2c25",
"taskDefinitionKey": "QuickEvaluation",
"caseExecutionId": null,
"caseInstanceId": null,
"caseDefinitionId": null,
"suspended": false,
"formKey": "a8apps:suryoday:gng:v0.1.0:kycUpload",
"tenantId": null
},
{
"_links": {
"assignee": {
"href": "/user/demo"
},
"execution": {
"href": "/execution/412a03b7-06ae-11ea-8860-120ef5ab2c25"
},
"identityLink": {
"href": "/task/412a2aca-06ae-11ea-8860-120ef5ab2c25/identity-links"
},
"processDefinition": {
"href": "/process-definition/quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25"
},
"processInstance": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25"
},
"self": {
"href": "/task/412a2aca-06ae-11ea-8860-120ef5ab2c25"
}
},
"_embedded": {
"variable": [
{
"_links": {
"self": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25/variables/loanAmount"
}
},
"_embedded": null,
"name": "loanAmount",
"value": "650000",
"type": "String",
"valueInfo": {}
},
{
"_links": {
"self": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25/variables/firstName"
}
},
"_embedded": null,
"name": "firstName",
"value": "Kamesh",
"type": "String",
"valueInfo": {}
}
]
},
"id": "412a2aca-06ae-11ea-8860-120ef5ab2c25",
"name": "Quick Evaluation",
"assignee": "demo",
"created": "2019-11-14T07:13:27.558+0000",
"due": null,
"followUp": null,
"delegationState": null,
"description": null,
"executionId": "412a03b7-06ae-11ea-8860-120ef5ab2c25",
"owner": null,
"parentTaskId": null,
"priority": 50,
"processDefinitionId": "quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25",
"processInstanceId": "412a03b7-06ae-11ea-8860-120ef5ab2c25",
"taskDefinitionKey": "QuickEvaluation",
"caseExecutionId": null,
"caseInstanceId": null,
"caseDefinitionId": null,
"suspended": false,
"formKey": "a8apps:suryoday:gng:v0.1.0:kycUpload",
"tenantId": null
}
]
},
"count": 13
}
这是您的请求:
// MARK: - URLRequestConvertible
func asURLRequest() throws -> URLRequest {
let url = try K.ProductionServer.baseURL.asURL()
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
print(urlRequest)
// HTTP Method
urlRequest.httpMethod = method.rawValue
let authToken = UserDefaults.standard.string(forKey: "authToken")
let bearerToken: String = "Bearer " + (authToken ?? "")
print("baearer token::\(bearerToken)")
// Common Headers
urlRequest.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.acceptType.rawValue)
urlRequest.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.contentType.rawValue)
urlRequest.setValue(bearerToken, forHTTPHeaderField: HTTPHeaderField.authentication.rawValue)
// Parameters
if let parameters = parameters {
do {
urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
} catch {
throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
}
}
return urlRequest
}
以下是alamofire请求:
import Foundation
import Alamofire
public class APIClient {
@discardableResult
private static func performRequest<T:Decodable>(route:APIRouter, decoder: JSONDecoder = JSONDecoder(), completion:@escaping (AFResult<T>)->Void) -> DataRequest {
return AF.request(route)
.responseDecodable (decoder: decoder){ (response: AFDataResponse<T>) in
completion(response.result)
print("framework response::",response.result)
}
}
public static func taskID(id: String, completion:@escaping (AFResult< [TaskID]>)->Void) {
performRequest(route: APIRouter.TaskById(id: id), completion: completion)
}
}//APIClient
<代码>导入基础
进口阿拉莫菲尔
公共类客户端{
@可丢弃结果
私有静态func performRequest(路由:APIRouter,解码器:JSONDecoder=JSONDecoder(),完成:@escaping(AFResult)->Void)->DataRequest{
返回AF.request(路由)
.responseDecodable(解码器:解码器){(响应:AFDataResponse)在
完成(响应、结果)
打印(“框架响应::”,response.result)
}
}
public static func taskID(id:String,completion:@escaping(AFResult<[taskID]>)->Void){
performRequest(路由:APIRouter.TaskById(id:id),完成:完成)
}
}//APIClient
最初它显示的是字典,Swift.DecodingError.Context(codingPath:[],debugDescription:“本应解码字典,但却找到了一个数组。但现在我在控制台日志中得到了nil。不知道为什么会得到nil值。根据我的json响应,struct是否正确?我正在努力获取嵌套数据
非常感谢您的任何帮助。您的结构是正确的。请参阅下面的游乐场以获得证明;我没有得到错误。
nil
是非常常见的结果,当您没有完整的数据集,并且您假设响应中的某个可选字段是非可选的,因为您在示例数据中看到它(您的样品不一定具有代表性)。如果服务器没有实际的规范,您需要找出哪些字段无法解码,并且可能需要获取一组数据以确定哪些字段是真正可选的。您可以通过在上面的AF项目中输入错误处理代码或将响应粘贴到下面的“我的游乐场”中来完成此操作。无论哪种方式,解码ing错误应该告诉您哪个字段不存在
import PlaygroundSupport
import UIKit
import WebKit
public struct TaskID: Decodable {
let embedded: Embedded?
let count: Int?
enum CodingKeys: String, CodingKey {
case count = "count"
case embedded = "_embedded"
}
}
public struct Embedded: Decodable {
let task: [Task]?
enum CodingKeys: String, CodingKey {
case task = "task"
}
}
public struct Task : Decodable {
let id : String?
let name: String?
let assignee: String?
let created: String?
let processDefinitionId: String?
enum CodingKeys: String, CodingKey {
case id = "id"
case name = "name"
case assignee = "assignee"
case created = "created"
case processDefinitionId = "processDefinitionId"
}
}
let data = """
{
"_links": {
"self": {
"href": "/task"
}
},
"_embedded": {
"task": [
{
"_links": {
"assignee": {
"href": "/user/demo"
},
"execution": {
"href": "/execution/1b64cf75-0616-11ea-8860-120ef5ab2c25"
},
"identityLink": {
"href": "/task/1b64f688-0616-11ea-8860-120ef5ab2c25/identity-links"
},
"processDefinition": {
"href": "/process-definition/quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25"
},
"processInstance": {
"href": "/process-instance/1b64cf75-0616-11ea-8860-120ef5ab2c25"
},
"self": {
"href": "/task/1b64f688-0616-11ea-8860-120ef5ab2c25"
}
},
"_embedded": {
"variable": []
},
"id": "1b64f688-0616-11ea-8860-120ef5ab2c25",
"name": "Quick Evaluation",
"assignee": "demo",
"created": "2019-11-13T13:04:20.687+0000",
"due": null,
"followUp": null,
"delegationState": null,
"description": null,
"executionId": "1b64cf75-0616-11ea-8860-120ef5ab2c25",
"owner": null,
"parentTaskId": null,
"priority": 50,
"processDefinitionId": "quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25",
"processInstanceId": "1b64cf75-0616-11ea-8860-120ef5ab2c25",
"taskDefinitionKey": "QuickEvaluation",
"caseExecutionId": null,
"caseInstanceId": null,
"caseDefinitionId": null,
"suspended": false,
"formKey": "a8apps:suryoday:gng:v0.1.0:kycUpload",
"tenantId": null
},
{
"_links": {
"assignee": {
"href": "/user/demo"
},
"execution": {
"href": "/execution/412a03b7-06ae-11ea-8860-120ef5ab2c25"
},
"identityLink": {
"href": "/task/412a2aca-06ae-11ea-8860-120ef5ab2c25/identity-links"
},
"processDefinition": {
"href": "/process-definition/quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25"
},
"processInstance": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25"
},
"self": {
"href": "/task/412a2aca-06ae-11ea-8860-120ef5ab2c25"
}
},
"_embedded": {
"variable": [
{
"_links": {
"self": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25/variables/loanAmount"
}
},
"_embedded": null,
"name": "loanAmount",
"value": "650000",
"type": "String",
"valueInfo": {}
},
{
"_links": {
"self": {
"href": "/process-instance/412a03b7-06ae-11ea-8860-120ef5ab2c25/variables/firstName"
}
},
"_embedded": null,
"name": "firstName",
"value": "Kamesh",
"type": "String",
"valueInfo": {}
}
]
},
"id": "412a2aca-06ae-11ea-8860-120ef5ab2c25",
"name": "Quick Evaluation",
"assignee": "demo",
"created": "2019-11-14T07:13:27.558+0000",
"due": null,
"followUp": null,
"delegationState": null,
"description": null,
"executionId": "412a03b7-06ae-11ea-8860-120ef5ab2c25",
"owner": null,
"parentTaskId": null,
"priority": 50,
"processDefinitionId": "quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25",
"processInstanceId": "412a03b7-06ae-11ea-8860-120ef5ab2c25",
"taskDefinitionKey": "QuickEvaluation",
"caseExecutionId": null,
"caseInstanceId": null,
"caseDefinitionId": null,
"suspended": false,
"formKey": "a8apps:suryoday:gng:v0.1.0:kycUpload",
"tenantId": null
}
]
},
"count": 13
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
do {
let decoded = try decoder.decode(TaskID.self, from: data)
print(decoded)
} catch ( let error ) {
print(error.localizedDescription)
}
此外,如果您感到懒惰,您可以使用,因为nil
是来自decodable的一个非常常见的响应,您可以使用DataRequest的扩展来解析请求并从请求中获取值,就像使用responseDecodable
,这里您可以使用类似的方法
extension DataRequest {
fileprivate func decodableResponseSerializer<T: Decodable>() -> DataResponseSerializer<T> {
return DataResponseSerializer { _, response, data, error in
guard error == nil else { return .failure(error!) }
guard let data = data else {
return .failure(AFError.responseSerializationFailed(reason: .inputDataNil))
}
return Result { try newJSONDecoder().decode(T.self, from: data) }
}
}
@discardableResult
fileprivate func responseDecodable<T: Decodable>(queue: DispatchQueue? = nil, completionHandler: @escaping (DataResponse<T>) -> Void) -> Self {
return response(queue: queue, responseSerializer: decodableResponseSerializer(), completionHandler: completionHandler)
}
}
扩展数据请求{
fileprivate func decodableResponseSerializer()->DataResponseSerializer{
返回DataResponseSerializer{},响应,数据,中的错误
guard error==nil else{return.failure(error!)}
guard let data=其他数据{
return.failure(AFError.responseSerialization失败(原因:.inputDataNil))
}
返回结果{try newJSONDecoder().decode(T.self,from:data)}
}
}
@可丢弃结果
fileprivate func responseDecodable(队列:DispatchQueue?=nil,completionHandler:@escaping(DataResponse)->Void)->Self{
返回响应(队列:队列,响应序列化程序:decodableResponseSerializer(),completionHandler:completionHandler)
}
}
然后你可以这样称呼它
Alamofire.request(url, method:.post, parameters: parameters, headers: headers)
.responseDecodable { (response: DataResponse< Task >) in completion(response.result) }
Alamofire.request(url,方法:.post,参数:参数,标题:标题)
.responseDecodable{(响应:DataResponse)正在完成(response.result)}
当您得到类似的结果时,只有当您有不同类型的数据而不是您指定的数据时,才会出现此问题。谢谢您的回答。.我怀疑我是否需要传入数组或类。func taskID(id:String,completion:@escaping(AFResult)->void仍然面临相同的问题我也有url请求代码。你能检查一下吗包装器是
TaskID
,就像我的例子一样。不用使用AF ResponsedCodeTable,只需要获取数据并自己解码,这样你就可以捕捉解码错误并找出哪个字段失败了。这和另外两个任务有什么区别你最近几天发布的离子?它们看起来非常相似。@JoakimDanielson最后两个问题我有编码键,希望解码字典,但找到了一个数组。但是现在我得到了零值。你能帮我解决这个问题吗this@JoakimDanielson现在我有了url请求代码,但我和其他人已经试过帮助你一次了对于你的json,你似乎仍然在为同样的事情而挣扎。我并不认为这有什么意义,因为没有什么真正的改变。你需要用你的代码来区分可能的问题,实际的json解码(这很好)以及您需要的AF和ApiClient类have@JoakimDanielson,好的,我有一个疑问,我是否需要在数组中传递结构名,还是只传递类名。公共静态func taskID(id:String,completion:@escaping(AFResult<[taskID]>)如果我传递taskID,它会显示错误,预期会解码字典,但找到数组。如果我改为数组[taskID]它打印零值。
Alamofire.request(url, method:.post, parameters: parameters, headers: headers)
.responseDecodable { (response: DataResponse< Task >) in completion(response.result) }