![](/img/trans.png)
[英]Swift parse json from API - The data couldn’t be read because it isn’t in the correct format
[英]swift parse json - The data couldn’t be read because it isn’t in the correct format
這是結構編碼代碼:
import Foundation
public struct TaskID: Codable {
let embedded: Embedded
}
public struct Embedded: Codable {
let task: [Task]
}
public struct Task : Codable {
let embedded: EmbeddedVariable
let id : String
let name: String
let assignee: String
let created: String
let processDefinitionId: String
}
public struct EmbeddedVariable: Codable {
let variable : [Variables]
}
public struct Variables: Codable {
let value : String
let name: String
}
我已經嘗試過codingKey,也嘗試過使用_embedded。 面臨同樣的問題。
錯誤日志:由於錯誤無法解碼響應:
Alamofire.AFError.
ResponseSerializationFailureReason.decodingFailed(error: Swift.DecodingError.typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil)))))
無法讀取數據,因為它的格式不正確。
這是 JSONSerialization 的代碼:
// 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
}
這是代碼 json 返回響應:
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<MyTaskData>)->Void) {
performRequest(route: APIRouter.TaskById(id: id), completion: completion)
}
}//APIClient
在您的 JSON 有效負載中,關鍵processDefinitionId的值末尾有一個額外的逗號。
試試這個 JSON 格式化工具來驗證 JSON: jsonformatter
"task":[
{
//...
"id": "412a2aca-06ae-11ea-8860-120ef5ab2c25",
"name": "Quick Evaluation",
"assignee": "demo",
"created": "2019-11-14T07:13:27.558+0000",
"processDefinitionId": "quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25", // remove this coma(,) from this line
}
更新:
對_embedded
CodingKey
試試下面的方法
// MARK: - TaskID
struct TaskID: Codable {
let embedded: Embedded
let count: Int
enum CodingKeys: String, CodingKey {
case embedded = "_embedded"
case count
}
}
// MARK: - Embedded
struct Embedded: Codable {
let task: [Task]
}
// MARK: - Task
struct Task: Codable {
let embedded: EmbeddedVariable
let id, name, assignee, created: String
let processDefinitionID: String
enum CodingKeys: String, CodingKey {
case embedded = "_embedded"
case id, name, assignee, created
case processDefinitionID = "processDefinitionId"
}
}
// MARK: - EmbeddedVariable
struct EmbeddedVariable: Codable {
let variable: [Variable]
}
// MARK: - Variable
struct Variable: Codable {
let links: Links
let name, value, type: String
let valueInfo: ValueInfo
enum CodingKeys: String, CodingKey {
case links = "_links"
case name, value, type, valueInfo
}
}
// MARK: - Links
struct Links: Codable {
let linksSelf: SelfClass
enum CodingKeys: String, CodingKey {
case linksSelf = "self"
}
}
// MARK: - SelfClass
struct SelfClass: Codable {
let href: String
}
// MARK: - ValueInfo
struct ValueInfo: Codable {
}
在可編碼結構中將所有embeded
更改為_embeded
怎么樣?
在您的APIClient
class 中,默認創建JSONDecoder
實例。 並且在解碼過程中不會更改鍵名包括下划線。
JSONDecoder.KeyDecodingStrategy.useDefaultKeys
策略是您未指定時使用的策略。 來自 Apple 的文檔
public struct TaskID: Codable {
let _embedded: Embedded
}
public struct Task : Codable {
let _embedded: EmbeddedVariable
let id : String
let name: String
let assignee: String
let created: String
let processDefinitionId: String
}
嘗試使用 QuickType.io
// MARK: - Welcome
struct Welcome: Codable {
let embedded: WelcomeEmbedded
let count: Int
enum CodingKeys: String, CodingKey {
case embedded = "_embedded"
case count
}
}
從 Alamofire 響應中解析值:
Alamofire.request(url).responseWelcomeEmbedded { response in if let welcomeEmbedded = response.result.value {... } }
// MARK: - WelcomeEmbedded
struct WelcomeEmbedded: Codable {
let task: [Task]
}
從 Alamofire 響應中解析值:
Alamofire.request(url).responseTask { response in if let task = response.result.value {... } }
// MARK: - Task
struct Task: Codable {
let embedded: TaskEmbedded
let id, name, assignee, created: String
let processDefinitionID: String
enum CodingKeys: String, CodingKey {
case embedded = "_embedded"
case id, name, assignee, created
case processDefinitionID = "processDefinitionId"
}
}
從 Alamofire 響應中解析值:
Alamofire.request(url).responseTaskEmbedded { response in if let taskEmbedded = response.result.value {... } }
// MARK: - TaskEmbedded
struct TaskEmbedded: Codable {
let variable: [Variable]
}
從 Alamofire 響應中解析值:
Alamofire.request(url).responseVariable { response in if let variable = response.result.value {... } }
// MARK: - Variable
struct Variable: Codable {
let links: Links
let embedded: JSONNull?
let name, value, type: String
let valueInfo: ValueInfo
enum CodingKeys: String, CodingKey {
case links = "_links"
case embedded = "_embedded"
case name, value, type, valueInfo
}
}
從 Alamofire 響應中解析值:
Alamofire.request(url).responseLinks { response in if let links = response.result.value {... } }
// MARK: - Links
struct Links: Codable {
let linksSelf: SelfClass
enum CodingKeys: String, CodingKey {
case linksSelf = "self"
}
}
To parse values from Alamofire responses: Alamofire.request(url).responseSelfClass { response in if let selfClass = response.result.value {... } }
// MARK: - SelfClass
struct SelfClass: Codable {
let href: String
}
從 Alamofire 響應中解析值:
Alamofire.request(url).responseValueInfo { response in if let valueInfo = response.result.value {... } }
// MARK: - ValueInfo
struct ValueInfo: Codable {
}
// MARK: - Helper functions for creating encoders and decoders
func newJSONDecoder() -> JSONDecoder {
let decoder = JSONDecoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
decoder.dateDecodingStrategy = .iso8601
}
return decoder
}
func newJSONEncoder() -> JSONEncoder {
let encoder = JSONEncoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
encoder.dateEncodingStrategy = .iso8601
}
return encoder
}
// MARK: - Alamofire response handlers
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)
}
@discardableResult
func responseWelcome(queue: DispatchQueue? = nil, completionHandler: @escaping (DataResponse<Welcome>) -> Void) -> Self {
return responseDecodable(queue: queue, completionHandler: completionHandler)
}
}
這是一個基本的 Alamofire 請求。 如果使用下面的結構解析json應該不會出錯。
Alamofire.request(url, headers: headers).responseJSON { response in
switch response.result {
case .success(let value):
let jsonData = value as! NSDictionary
completionHandler(jsonData, nil)
print("****** JSON \(jsonData)")
case .failure(let error):
completionHandler(nil, error)
}
在這里,我將它放在您的代碼中。 您應該嘗試如下所示的標題。 您需要填寫適當的標題。
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)
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"Authorization": "Basic " + currentToken
]
Alamofire.request(url, headers: headers).responseJSON { response in
switch response.result {
case .success(let value):
let jsonData = value as! NSDictionary
completionHandler(jsonData, nil)
print("****** JSON \(jsonData)")
case .failure(let error):
completionHandler(nil, error)
}
//return urlRequest
}
希望這可以幫助
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.