我有一个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))
}
用法:
请尝试以下内容作为AppDelegate
的didFinishLaunchingWithOptions
中的证明
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