【问题标题】:Trouble implementing Swift Result<Success, Error> in API request在 API 请求中实现 Swift Result<Success, Error> 时遇到问题
【发布时间】:2021-02-12 00:29:32
【问题描述】:

我有意创建一个已存在于 MongoDB 中的用户,以向用户显示错误消息,例如“请选择其他用户名”或“电子邮件已在使用中”,但我无法解码服务器的响应。

我的模型旨在处理成功(用户/令牌)或错误响应(消息)...

当在后端创建帐户时,我能够成功解码用户对象...

我做错了什么?我觉得我应该以某种方式为错误模型使用枚举??

// POSTMAN RESPONSE WHEN USERNAME ALREADY TAKEN
{
    "success": false,
    "message": "Please choose a different username"
}

// XCODE ERROR MESSAGE 

//...Expected to decode Dictionary<String, Any> but found a string/data 
//instead.", underlyingError: nil))

// DATA MODELS

struct UserResponse: Decodable {
    let success: Bool
    let message: ErrorResponse?
    var user: User?
    var token: String?
}

struct ErrorResponse: Decodable, Error {
    let message: String
}
class LoginService {
    
     static func createAccount(username: String, email: String, password: String, 
completion: @escaping(Result <UserResponse, Error>) -> Void) {
     
        let user = UserSignup(username: username, email: email, password: password)
        
        // Create URL code
       
        do {
            let encoder = JSONEncoder()
            urlRequest.httpBody = try encoder.encode(user)
           
            let dataTask = URLSession.shared.dataTask(with: urlRequest) { data, response, error in
               
                if let error = error {
                    completion(.failure(error))
                    return
                }
                guard let jsonData = data else { return }
    
                do {
                    let responseObject = try JSONDecoder().decode(UserResponse.self, from: jsonData)
                    switch responseObject.success {
                    case true:
                        completion(.success(responseObject))
                    case false:
                        // not working
                        guard let errorMessage = responseObject.message else {
                          return
                        }
                        completion(.failure(errorMessage))
                    }
                } catch {
                    print(error)
                }
            }
            dataTask.resume()
        } catch {
            // handle error
        }
    }

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    错误显示message 是一个字符串,因此将其声明为String

    struct UserResponse: Decodable {
        let success: Bool
        let message: String?
        var user: User?
        var token: String?
    }
    

    我觉得我应该以某种方式为错误模型使用枚举

    摆脱可选项是个好主意。枚举首先解码status,然后根据值解码成功时的usertoken,失败时解码错误message

    struct UserResponse {
        let user: User
        let token: String
    }
    
    enum Response : Decodable {
        case success(UserResponse)
        case failure(String)
        
        private enum CodingKeys : String, CodingKey { case success, message, user, token }
        
        init(from decoder : Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            let success = try container.decode(Bool.self, forKey: .success)
            if success {
                let user = try container.decode(User.self, forKey: .user)
                let token = try container.decode(String.self, forKey: .token)
                self = .success(UserResponse(user: user, token: token))
            } else {
                let message = try container.decode(String.self, forKey: .message)
                self = .failure(message)
            }
        }
    }
    

    然后你可以替换

       let responseObject = try JSONDecoder().decode(UserResponse.self, from: jsonData)
        switch responseObject.success {
        case true:
            completion(.success(responseObject))
        case false:
            // not working
            guard let errorMessage = responseObject.message else {
              return
            }
            completion(.failure(errorMessage))
        }
    

       let response = try JSONDecoder().decode(Response.self, from: jsonData)
        switch response {
        case .success(let responseObject):
            completion(.success(responseObject))
        case .failure(let errorMessage)
            completion(.failure(errorMessage))
        }
    

    【讨论】:

    • 非常感谢 vadian :)
    • 非常好的解决方案:)
    • 你必须声明一个符合Error的枚举,例如enum UserError : Error { case userExists(String) }然后你可以写completion(.failure(UserError.userExists(errorMessage)))
    猜你喜欢
    • 2022-12-04
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多