从 json 到 Swift 中的结构解码失败
Decode failure from json to struct in Swift
我正在构建代码以使用 Swift 调用 post 请求。现在我需要解码结构对象中的 json 响应。
响应 json 像这样:
{
"result": {
"id": "64",
"home_address": "",
"other_address": "",
"first_name": "Maicol",
"category_id": "4",
"last_name": "Casarotti",
"phone": "3332211111",
"password": "maicol",
"email": "maicol@maicol.it",
"description": "utente",
"type": "user",
"social_id": "",
"image": "http://www.arrivaarrivaitalia.com/Arriva/uploads/images/",
"address": "address",
"store_address": "cabotto",
"zipcode": "71043",
"lat": "456",
"lon": "789",
"register_id": "",
"ios_register_id": "",
"status": "deactive",
"off_on": "online",
"date_time": "2021-04-19 05:51:50",
"open_time": "",
"close_time": "",
"weekly_time": "",
"certificate_image": "",
"weekly_off": ""
},
"message": "successfull",
"status": "1"
}
这是我在 swift 上构建的结构 UserModel:
import Foundation
struct UserModel:Codable {
var first_name: String?
var last_name: String?
var type: String?
var password: String?
var email: String?
var phone: String?
var category_id: String?
var address: String?
var lat: String?
var lon: String?
var description: String?
var store_address: String?
var zipcode: String?
var register_id: String?
mutating func removeAll() {
self = UserModel()
}
}
通过这种方法,我可以发出 post 请求:
func signup(user: UserModel, completition: @escaping(Result<UserModel,APIError>)->Void){
do{
var urlRequest = URLRequest(url: resourceURL)
urlRequest.httpMethod = "POST"
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = try JSONEncoder().encode(user)
let dataTask = URLSession.shared.dataTask(with: urlRequest){
data, response, _ in
print("Data Str: \(String(data: data!, encoding: .utf8))");
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200,
let jsonData = data else{
completition(.failure(.responseProblem))
return
}
do{
let messageData = try JSONDecoder().decode(UserModel.self, from: jsonData)
completition(.success(messageData))
}catch{
completition(.failure(.decodingProblem))
}
}
dataTask.resume()
}catch{
completition(.failure(.encodingProblem))
}
}
如果我进行调试,messageData 为 nil。
您的 JSON 模型应该是这样的:
struct UserModel : Codable {
let result: Result?
let message: String?
let status: String?
enum CodingKeys: String, CodingKey {
case result = "result"
case message = "message"
case status = "status"
}
struct Result: Codable {
let id: String?
let home_address: String?
let other_address: String?
let first_name: String?
let category_id: String?
let last_name: String?
let phone: String?
let password: String?
let email: String?
let description: String?
let type: String?
let social_id: String?
let image: String?
let address: String?
let store_address: String?
let zipcode: String?
let lat: String?
let lon: String?
let register_id: String?
let ios_register_id: String?
let status: String?
let off_on: String?
let date_time: String?
let open_time: String?
let close_time: String?
let weekly_time: String?
let certificate_image: String?
let weekly_off: String?
enum CodingKeys: String, CodingKey {
case id = "id"
case home_address = "home_address"
case other_address = "other_address"
case first_name = "first_name"
case category_id = "category_id"
case last_name = "last_name"
case phone = "phone"
case password = "password"
case email = "email"
case description = "description"
case type = "type"
case social_id = "social_id"
case image = "image"
case address = "address"
case store_address = "store_address"
case zipcode = "zipcode"
case lat = "lat"
case lon = "lon"
case register_id = "register_id"
case ios_register_id = "ios_register_id"
case status = "status"
case off_on = "off_on"
case date_time = "date_time"
case open_time = "open_time"
case close_time = "close_time"
case weekly_time = "weekly_time"
case certificate_image = "certificate_image"
case weekly_off = "weekly_off"
}
}
}
P.S: 转换成camelCase
.
会更好
要解码 json 你可以使用一个小帮手:
func decodeResponseData<T: Codable>(responseType: T.Type, data: Data) -> Swift.Result<T, Error> {
do {
let apiResponse = try JSONDecoder().decode(responseType, from: data)
return (.success(apiResponse))
} catch let DecodingError.dataCorrupted(context) {
print("# Data corrupted: ", context.debugDescription)
print(context)
return (.failure(NetworkResponseError.decodingDataCorrupted))
} catch let DecodingError.keyNotFound(key, context) {
print("# Key '\(key)' not found:", context.debugDescription)
print("# CodingPath:", context.codingPath)
return (.failure(NetworkResponseError.decodingKeyNotFound))
} catch let DecodingError.valueNotFound(value, context) {
print("# Value '\(value)' not found:", context.debugDescription)
print("# CodingPath:", context.codingPath)
return (.failure(NetworkResponseError.decodingValueNotFound))
} catch let DecodingError.typeMismatch(type, context) {
print("# Type '\(type)' mismatch:", context.debugDescription)
print("# CodingPath:", context.codingPath)
return (.failure(NetworkResponseError.decodingTypeMismatch))
} catch {
return (.failure(error))
}
}
enum NetworkResponseError: String, Error {
case decodingDataCorrupted = "Decoding Error: Data corruoted."
case decodingKeyNotFound = "Decoding Error: Decoding key not found"
case decodingValueNotFound = "Decoding Error: Decoding value not found"
case decodingTypeMismatch = "Decoding Error: Type mismatch"
}
要解码,您可以像这样使用它:
if let _data = response.data {
let jsonModelDecoded = self.decodeResponseData(responseType: UserModel.self, data: _data)
} else {
//throw an error or handle the error
}
我正在构建代码以使用 Swift 调用 post 请求。现在我需要解码结构对象中的 json 响应。 响应 json 像这样:
{
"result": {
"id": "64",
"home_address": "",
"other_address": "",
"first_name": "Maicol",
"category_id": "4",
"last_name": "Casarotti",
"phone": "3332211111",
"password": "maicol",
"email": "maicol@maicol.it",
"description": "utente",
"type": "user",
"social_id": "",
"image": "http://www.arrivaarrivaitalia.com/Arriva/uploads/images/",
"address": "address",
"store_address": "cabotto",
"zipcode": "71043",
"lat": "456",
"lon": "789",
"register_id": "",
"ios_register_id": "",
"status": "deactive",
"off_on": "online",
"date_time": "2021-04-19 05:51:50",
"open_time": "",
"close_time": "",
"weekly_time": "",
"certificate_image": "",
"weekly_off": ""
},
"message": "successfull",
"status": "1"
}
这是我在 swift 上构建的结构 UserModel:
import Foundation
struct UserModel:Codable {
var first_name: String?
var last_name: String?
var type: String?
var password: String?
var email: String?
var phone: String?
var category_id: String?
var address: String?
var lat: String?
var lon: String?
var description: String?
var store_address: String?
var zipcode: String?
var register_id: String?
mutating func removeAll() {
self = UserModel()
}
}
通过这种方法,我可以发出 post 请求:
func signup(user: UserModel, completition: @escaping(Result<UserModel,APIError>)->Void){
do{
var urlRequest = URLRequest(url: resourceURL)
urlRequest.httpMethod = "POST"
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = try JSONEncoder().encode(user)
let dataTask = URLSession.shared.dataTask(with: urlRequest){
data, response, _ in
print("Data Str: \(String(data: data!, encoding: .utf8))");
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200,
let jsonData = data else{
completition(.failure(.responseProblem))
return
}
do{
let messageData = try JSONDecoder().decode(UserModel.self, from: jsonData)
completition(.success(messageData))
}catch{
completition(.failure(.decodingProblem))
}
}
dataTask.resume()
}catch{
completition(.failure(.encodingProblem))
}
}
如果我进行调试,messageData 为 nil。
您的 JSON 模型应该是这样的:
struct UserModel : Codable {
let result: Result?
let message: String?
let status: String?
enum CodingKeys: String, CodingKey {
case result = "result"
case message = "message"
case status = "status"
}
struct Result: Codable {
let id: String?
let home_address: String?
let other_address: String?
let first_name: String?
let category_id: String?
let last_name: String?
let phone: String?
let password: String?
let email: String?
let description: String?
let type: String?
let social_id: String?
let image: String?
let address: String?
let store_address: String?
let zipcode: String?
let lat: String?
let lon: String?
let register_id: String?
let ios_register_id: String?
let status: String?
let off_on: String?
let date_time: String?
let open_time: String?
let close_time: String?
let weekly_time: String?
let certificate_image: String?
let weekly_off: String?
enum CodingKeys: String, CodingKey {
case id = "id"
case home_address = "home_address"
case other_address = "other_address"
case first_name = "first_name"
case category_id = "category_id"
case last_name = "last_name"
case phone = "phone"
case password = "password"
case email = "email"
case description = "description"
case type = "type"
case social_id = "social_id"
case image = "image"
case address = "address"
case store_address = "store_address"
case zipcode = "zipcode"
case lat = "lat"
case lon = "lon"
case register_id = "register_id"
case ios_register_id = "ios_register_id"
case status = "status"
case off_on = "off_on"
case date_time = "date_time"
case open_time = "open_time"
case close_time = "close_time"
case weekly_time = "weekly_time"
case certificate_image = "certificate_image"
case weekly_off = "weekly_off"
}
}
}
P.S: 转换成camelCase
.
要解码 json 你可以使用一个小帮手:
func decodeResponseData<T: Codable>(responseType: T.Type, data: Data) -> Swift.Result<T, Error> {
do {
let apiResponse = try JSONDecoder().decode(responseType, from: data)
return (.success(apiResponse))
} catch let DecodingError.dataCorrupted(context) {
print("# Data corrupted: ", context.debugDescription)
print(context)
return (.failure(NetworkResponseError.decodingDataCorrupted))
} catch let DecodingError.keyNotFound(key, context) {
print("# Key '\(key)' not found:", context.debugDescription)
print("# CodingPath:", context.codingPath)
return (.failure(NetworkResponseError.decodingKeyNotFound))
} catch let DecodingError.valueNotFound(value, context) {
print("# Value '\(value)' not found:", context.debugDescription)
print("# CodingPath:", context.codingPath)
return (.failure(NetworkResponseError.decodingValueNotFound))
} catch let DecodingError.typeMismatch(type, context) {
print("# Type '\(type)' mismatch:", context.debugDescription)
print("# CodingPath:", context.codingPath)
return (.failure(NetworkResponseError.decodingTypeMismatch))
} catch {
return (.failure(error))
}
}
enum NetworkResponseError: String, Error {
case decodingDataCorrupted = "Decoding Error: Data corruoted."
case decodingKeyNotFound = "Decoding Error: Decoding key not found"
case decodingValueNotFound = "Decoding Error: Decoding value not found"
case decodingTypeMismatch = "Decoding Error: Type mismatch"
}
要解码,您可以像这样使用它:
if let _data = response.data {
let jsonModelDecoded = self.decodeResponseData(responseType: UserModel.self, data: _data)
} else {
//throw an error or handle the error
}