从 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
}