如何将JSON响应解析为模型并在表视图中加载



我有一个JSON响应,如下所示。

{
"data": [
{
"division": "Chemical",
"divisionid": 5
},
{
"division": "Corporate",
"divisionid": 12
},
{
"division": "Drilling",
"divisionid": 1
},
{
"division": "Energy",
"divisionid": 2
}
],
"response": {
"code": "413",
"message": "Success",
"status": "True",
"userToken": "XXXX"
}
}

我的模型类如下

struct ApiResponse<T: Codable>: Codable {
let data: T
let response: Response
}
struct Division: Codable {
let divisionid: Int
let division: String
}
struct Response: Codable {
let code: String
let message: String
let status: String
let userToken: String
} 

我打电话给Api,如下所示

调用部件

getDivisions () { result in
switch result {
case .success(let divisions):
print(divisions)
case .failure(let error):
print("Error: (error.localizedDescription)")
}
}

定义部分

func getDivisions(completed: @escaping (Result<[Division], ApiErrors>) -> Void) {

let endpoint = BaseUrl + ApiEndPoint.DivisionsList.description

guard let url = URL(string: endpoint) else {
completed(.failure(.invalidUsername))
return
}
guard (String(describing: UserDefaults.standard.string(forKey: "AuthCode"))) != "" else {
completed(.failure(.invalidAuthToken))
return
}

let localParameters: [String: Any] = [
"userToken": (UserDefaults.standard.string(forKey: "userTokenBI")) ?? "Default"
]

print("Auth Code retrieved: (UserDefaults.standard.string(forKey: "authCodeUTS") ?? "Failed to get value")")
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")  // the request is JSON
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")        // the expected response is also JSON
request.setValue("Basic (String(describing: UserDefaults.standard.string(forKey: "authCodeUTS")))", forHTTPHeaderField: "Authorization")
request.timeoutInterval = 60.0

do {
request.httpBody = try JSONSerialization.data(withJSONObject: localParameters, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
}

let task = URLSession.shared.dataTask(with: request) { data, response, error in

if let _ = error {
completed(.failure(.unableToComplete))
//return
}
//HTTP here

guard let data = data else {
completed(.failure(.invalidData))
return
}
do {
let response = try JSONDecoder().decode(ApiResponse<[Division]>.self, from: data)
completed(.success(response.data))
} catch {
print(error)
completed(.failure(.invalidData))
}
}
task.resume()
}

但是我无法将JSON响应中的数据返回到调用部分,因为解析没有正确完成。我得到的错误如下

dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.})))
Error: The operation couldn’t be completed.

有人能帮我解决我面临的问题吗?

提前感谢

我建议通过删除不必要的编码键和初始化程序来创建如下数据类型

struct ApiResponse: Codable {
let data: [Division]
let response: Response
}
struct Division: Codable {
let deptcode: String
let deptname: String
}
// MARK: - Response
struct Response: Codable {
let code: String
let message: String
let status: String
let userToken: String
} 

并如下更新getDivision方法签名和解码,

func getDivisions(completed: @escaping (Result<[Division], ApiErrors>) -> Void) {
//...
//...
do {
let response = try JSONDecoder().decode(ApiResponse.self, from: data)
completed(.success(response.data))
} catch {
print(error)
completed(.failure(.invalidData))
}
}

由于ApiResponse数据是通用的,因此更好的解决方案是将其声明为低于

struct ApiResponse<T: Codable>: Codable {
let data: T
let response: Response
}

现在,您可以解析预期来自API、的任何数据类型

do {
let response = try JSONDecoder().decode(ApiResponse<[Division]>.self, from: data)
completed(.success(response.data))
} catch {
print(error)
completed(.failure(.invalidData))
}

用法:

请尝试以下内容作为AppDelegatedidFinishLaunchingWithOptions中的证明

let data = """
{
"data": [
{
"division": "Chemical",
"divisionid": 5
},
{
"division": "Corporate",
"divisionid": 12
},
{
"division": "Drilling",
"divisionid": 1
},
{
"division": "Energy",
"divisionid": 2
}
],
"response": {
"code": "413",
"message": "Success",
"status": "True",
"userToken": "XXXX"
}
}
""".data(using: .utf8)!
do {
let response = try JSONDecoder().decode(ApiResponse<[Division]>.self, from: data)
response.data.forEach { print($0.division, $0.divisionid) }
} catch {
print(error)
}
// prints
Chemical 5
Corporate 12
Drilling 1
Energy 2

最新更新