【问题标题】:Swift - JSON decodingSwift - JSON 解码
【发布时间】:2021-07-28 03:10:01
【问题描述】:

我收到了来自 api 调用的 JSON 响应。问题是我得到不同的 JSON 响应,具体取决于用户是否输入了正确的凭据。我的问题是如何读取这些响应并将其解码为可用的结构,以及解码这些不同响应的最佳方法是什么。我注意到的一件事是两个响应都有一个可能有用的共同“isSuccess”。我几乎没有使用 swift 或阅读 JSON 的经验,所以这对我来说都是一次学习经历。

这是登录成功的响应

{"result":{"login":{"isAuthorized":true,"isEmpty":false,"userName":{"isEmpty":false,"name":{"firstName":"Jason","lastName":"Test","displayName":"Test, Jason","isEmpty":false,"fullName":"Jason Test"},"canDelete":false,"id":5793,"canModify":false},"username":"test@testable.com"},"parameters":{"isEmpty":false,"keep_logged_in_indicator":false,"username":"test@testable.com"}},"isAuthorized":true,"version":{"major":"2021","minor":"004","fix":"04","display":"2021.004.04","isEmpty":false},"isSystemDown":false,"timestamp":"2021-07-28T02:47:33Z","isSuccess":true}

这是对失败的回应

{"isAuthorized":true,"version":{"major":"2021","minor":"004","fix":"04","display":"2021.004.04","isEmpty":false},"isSystemDown":false,"errors":[{"password":"Unable to login as 'test@testable.com'"}],"timestamp":"2021-07-28T02:47:05Z","isSuccess":false}

这是我为我的 api 调用编写的代码

func request<T: Decodable>(endPoint: EndPoint, method: Method, parameters: [String: Any]? = nil, completion: @escaping(Result<T, Error>) -> Void) {
        // Creates a urlRequest
        guard let request = createRequest(endPoint: endPoint, method: method, parameters: parameters) else {
            completion(.failure(AppError.invalidUrl))
            return
        }
        
        let session = URLSession.shared
        
        session.dataTask(with: request) { data, response, error in
            var results: Result<Data, Error>?
            
            guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
                completion(.failure(AppError.badStatusCode))
                return
            }
            
            if let response = response {
                
                // Gets the JSESSIONID
                let cookieName = "JSESSIONID"
                if let cookie = HTTPCookieStorage.shared.cookies?.first(where: { $0.name == cookieName })  {
                    debugPrint("\(cookieName): \(cookie.value)")
                }
               
                print(response)
            }
            
            if let data = data {
                results = .success(data)
                
                // Converts data to readable String
                let responseString = String(data: data, encoding: .utf8) ?? "unable to convert to readable String"
                print("Server Response: \(responseString.description)")
 
            } else if let error = error {
                results = .failure(error)
                print("Server Error: \(error.localizedDescription)")
            }
            
            DispatchQueue.main.async {
                self.handleResponse(result: results, completion: completion)
            }
            
        }.resume()
    }
    

    private func handleResponse<T: Decodable>(result: Result<Data, Error>?, completion: (Result<T, Error>) -> Void) {
        guard let result = result else {
            completion(.failure(AppError.unknownError))
            return
        }
        
        switch result {
        
            case .success(let data):
                
                do {
                    let json = try JSONSerialization.jsonObject(with: data, options: [])
                    print("Server JsonObject response: \(json)")
                } catch {
                    completion(.failure(AppError.errorDecoding))
                }
                
                let decoder = JSONDecoder()
                // Decodes that json data
                do {
 
                } catch {
                    
                }
                
                
            case .failure(let error):
                completion(.failure(error))
        }
    }

我最感兴趣的是能够显示凭据不正确时发生的 json 错误。我的项目的截止日期正在逐渐临近,我们将不胜感激任何帮助或建议。

【问题讨论】:

  • 一个叫 createRequest 的家伙是哪里来的?方法?参数?它们是什么以及它们来自哪里?
  • 我建议阅读 Codable 而不是 JSONSerialization —— 网上有很多教程。另外,请查看网站 app.quicktype.io

标签: json swift generics


【解决方案1】:

您可以使用 Swift 的 Result 类型来区分成功结果和失败结果。

Result 类型默认是不可解码的,所以你需要像这样write a custom decoder

struct Response: Decodable {
    let result: Swift.Result<Result, Errors>

    enum CodingKeys: String, CodingKey {
        case isSuccess
        case errors
        case result
    }

    struct Result: Codable {
        let login: Login

        struct Login: Codable {
            let isAuthorized: Bool
        }
    }

    struct Errors: Error {
        let contents: [[String: String]]
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        if try container.decode(Bool.self, forKey: .isSuccess) {
            result = .success(try container.decode(Result.self, forKey: .result))
        } else {
            result = .failure(
                Errors(contents: try container.decode([[String: String]].self, forKey: .errors))
            )
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-14
    • 2020-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 2019-01-11
    相关资源
    最近更新 更多