问题描述
{
"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))
}
用法:
尝试以下作为didFinishLaunchingWithOptions
中AppDelegate
的证明
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