在iOS Swift中使用可编码解析嵌套的json响应数据?

时间:2019-11-18 05:56:24

标签: json swift xcode nested codable

我试图在swift 4中解析可解码的json数据。它显示nil值。我找不到这是什么问题?

这是模型类:

choseCard(card) => {
  const {playCard, player1} = this.state;

  return this.setState({
    playCard: playCard.concat(card),
    player1: player1.filter(c => c.id !== card.id)
  });
}

这是json:

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"


 }

}

这里是urlrequest:

{
"_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
}

以下是alamofire请求:

 // 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
}

最初显示的是字典,Swift.DecodingError.Context(codingPath:[],debugDescription:“预期用于解码Dictionary,但找到一个数组。,但是现在我在控制台日志中显示为nil。不知道为什么我得到nil值。根据我的json响应struct是否正确?我正在努力获取嵌套数据。

任何帮助,不胜感激。

2 个答案:

答案 0 :(得分:1)

您的结构正确。请参见下面的游乐场以获取证明;我没有错。如果您没有完整的数据集,并且假设响应中的某些可选字段是非可选的,则nil是非常常见的结果,因为您在示例数据中看到了该字段(您的示例不一定具有代表性)。如果没有服务器的实际规格,则需要确定哪个字段解码失败,并且可能需要获取一堆数据才能确定哪些字段真正是可选的。您可以通过在上面的AF项目中放入错误处理代码,或仅将响应粘贴到下面的我的游乐场中来实现。无论哪种方式,解码错误都可以告诉您不存在哪个字段。

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)
}

答案 1 :(得分:0)

import Foundation

// MARK: - Task
struct Task: Codable {
let links: VariableLinks?
let embedded: TaskEmbedded?
let count: Int?

enum CodingKeys: String, CodingKey {
    case links = "_links"
    case embedded = "_embedded"
    case count = "count"
}
}

// MARK: - TaskEmbedded
struct TaskEmbedded: Codable {
let task: [TaskElement]?

enum CodingKeys: String, CodingKey {
case task = "task"
}
}

// MARK: - TaskElement
struct TaskElement: Codable {
let links: TaskLinks?
let embedded: TaskEmbeddedClass?
let id: String?
let name: String?
let assignee: String?
let created: String?
let due: String?
let followUp: String?
let delegationState: String?
let taskDescription: String?
let executionId: String?
let owner: String?
let parentTaskId: Int?
let priority: Int?
let processDefinitionId: String?
let processInstanceId: String?
let taskDefinitionKey: String?
let caseExecutionId: Int?
let caseInstanceId: Int?
let caseDefinitionId: Int?
let suspended: Bool?
let formKey: String?
let tenantId: Int?

enum CodingKeys: String, CodingKey {
case links = "_links"
case embedded = "_embedded"
case id = "id"
case name = "name"
case assignee = "assignee"
case created = "created"
case due = "due"
case followUp = "followUp"
case delegationState = "delegationState"
case taskDescription = "description"
case executionId = "executionId"
case owner = "owner"
case parentTaskId = "parentTaskId"
case priority = "priority"
case processDefinitionId = "processDefinitionId"
case processInstanceId = "processInstanceId"
case taskDefinitionKey = "taskDefinitionKey"
case caseExecutionId = "caseExecutionId"
case caseInstanceId = "caseInstanceId"
case caseDefinitionId = "caseDefinitionId"
case suspended = "suspended"
case formKey = "formKey"
case tenantId = "tenantId"
}
}

// MARK: - TaskEmbeddedClass
struct TaskEmbeddedClass: Codable {
let variable: [Variable]?

enum CodingKeys: String, CodingKey {
case variable = "variable"
}
}

// MARK: - Variable
struct Variable: Codable {
let links: VariableLinks?
let embedded: String?
let name: String?
let value: String?
let type: String?
let valueInfo: ValueInfo?

enum CodingKeys: String, CodingKey {
case links = "_links"
case embedded = "_embedded"
case name = "name"
case value = "value"
case type = "type"
case valueInfo = "valueInfo"
}
}

// MARK: - VariableLinks
struct VariableLinks: Codable {
let linksSelf: SelfClass?

enum CodingKeys: String, CodingKey {
case linksSelf = "self"
}
}

// MARK: - SelfClass
struct SelfClass: Codable {
let href: String?

enum CodingKeys: String, CodingKey {
case href = "href"
}
}

// MARK: - ValueInfo
struct ValueInfo: Codable {
}

// MARK: - TaskLinks
struct TaskLinks: Codable {
let assignee: SelfClass?
let execution: SelfClass?
let identityLink: SelfClass?
let processDefinition: SelfClass?
let processInstance: SelfClass?
let linksSelf: SelfClass?

enum CodingKeys: String, CodingKey {
case assignee = "assignee"
case execution = "execution"
case identityLink = "identityLink"
case processDefinition = "processDefinition"
case processInstance = "processInstance"
case linksSelf = "self"
}
}

此外,如果您感到懒惰,可以使用quicktype.io,因为nil是可解码的非常常见的响应,因此您可以扩展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)
    }
}

然后您可以这样称呼

Alamofire.request(url, method:.post, parameters: parameters, headers: headers)
        .responseDecodable { (response: DataResponse< Task >) in completion(response.result) }

当您得到这样的信息时,它仅在您具有不同类型的数据而不是您指定的数据时出现。

相关问题