Swift 可解码返回对象

Swift 可解码返回对象,swift,api,decodable,Swift,Api,Decodable,我有一个可解码类: struct AuthenticationResponse : Decodable { var status: String var error: Error var access_token: String? = "" var expires_in: Double? = 0 var token_type: String? = "" var scope: String? = "" var refresh_token: String? = " } struct Error

我有一个可解码类:

struct AuthenticationResponse : Decodable {
var status: String
var error: Error
var access_token: String? = ""
var expires_in: Double? = 0
var token_type: String? = ""
var scope: String? = ""
var refresh_token: String? = " 
}

struct Error : Decodable {
var desc: String
var code: String
}
在Error类中,我有:

要解码到这个类,我有:

 URLSession.shared.dataTask(with: request) { (data:Data?, response:URLResponse?, error:Error?) in
            if let jsonData = data{
                let decoder = JSONDecoder()
                print("hey")
                print("response: \(String(data:jsonData, encoding:.utf8))")
                completion(try! decoder.decode(AuthenticationResponse.self, from: jsonData))
            }
    }.resume()
因为我收到的一些回复是(成功回复):

然后,一个失败的响应只包含一个包含desc和代码的错误对象

我试图实现的是一个适用于两种情况的可解码类(当响应成功和失败时),但是我不确定如何实现这一点。我知道我可以创建两个独立的可解码类,但这会使事情变得更混乱,因为我必须确定响应是否为错误,并填充以返回不同的类


“有人知道我应该如何理解< >/p> < p>我会给它一个<代码>尝试,但是首先我们需要整理出我认为是一个有点粗糙的问题。由于
Error
是一个(著名且广泛使用的)
协议的名称,因此应该重命名它,并且由于您希望能够在
AuthenticationResponse
中将其保留为空,因此它显然是一个可选选项(有一个问题,为什么它会出现在
响应
中,但我将把它放在一边)。这给我们留下了以下问题:

struct AuthError : Decodable {
    var desc: String
    var code: String
}

struct AuthenticationResponse : Decodable {
    var status: String
    var error: AuthError?
    var access_token: String? = ""
    var expires_in: Double? = 0
    var token_type: String? = ""
    var scope: String? = ""
    var refresh_token: String? = ""
}
然后我们需要两个相关案例的示例数据,我使用:

let okData = """
    {
    "status": "SUCCESS",
    "error": null,
    "access_token":
    "MWVmOWQxMDYwMjQyNDQ4NzQyNTdkZjQ3NmI4YmVjMGZjZGM5N2IyZmNkOTA1N2M0NDUzODEwYjM5ZWQyNGNkZg",
    "expires_in": 3600,
    "token_type": "bearer",
    "scope": null,
    "refresh_token":
    "ZGEwOGZiOWZhMzhhYjBmMzAyOGRmZTA5NjJhMjY2MTk3YzMyMmE1ZDlkNWI2NmJjYmIxMjNkMjE1NWFhNWY0Mg"
    }
    """.data(using: .utf8)!

let errData = """
    {
        "desc": "username or password incorrect",
        "code": "404"
    }
    """.data(using: .utf8)!
现在,我们可以定义单个
enum
返回类型,它允许我们的所有情况:

enum AuthResult {
    case ok(response: AuthenticationResponse)
    case authError(error: AuthError)
    case parseError(description: String)
    case fatal
}
这最终允许我们为接收到的身份验证数据编写
parse
函数:

func parse(_ jsonData:Data) -> AuthResult {
   let decoder = JSONDecoder()
    do {
        let authRes = try decoder.decode(AuthenticationResponse.self, from: jsonData)
        return .ok(response: authRes)
    } catch {
        do {
            let errRes = try decoder.decode(AuthError.self, from: jsonData)
            return .authError(error: errRes)
        } catch let errDecode {
            return .parseError(description: errDecode.localizedDescription)
        }
    }
}
所有这些在操场上都可以使用,就像在

switch parse(okData) {
case let .ok(response):
    print(response)
case let .authError(error):
    print(error)
case let .parseError(description):
    print("You threw some garbage at me and I was only able to \(description)")
default:
    print("don't know what to do here")
}
与大多数其他语言相比,这仍然是一种优雅的做法,但是调用仍然没有确定是否将
AuthenticationResponse
定义为
parse
函数的(常规)返回类型,并通过
throw
调用一些
enum
(符合
错误
)和一些合适的有效载荷

(主要)来自Java,我仍然避免使用异常作为“某种程度上”常规控制流(如“常规”登录失败),但考虑到Swifts更合理的异常处理方法,这可能需要重新考虑


无论如何,这就为您提供了一个解析服务应答的函数,以及一种“统一”处理它们的体面方法方式。由于您可能无法修改处理您的
请求的服务的行为,这可能是唯一可行的选择。但是,如果您能够修改服务,您应该争取“统一”只需调用
jsondeconder.decode
,即可解析的回复。您仍然需要解释选项(在上面的示例中,您应该这样做,因为它们仍然很难处理,即使考虑到Swifts brilliant编译器的支持,迫使您“做正确的事情”),但这会使您的解析更不容易出错。

不幸的是,您根本不清楚要做什么。在您的示例中,您已经有两个可解码类,是否要按原样使用它们?在这种情况下,如果解码,您可能必须创建自己的
AuthenticationResponse
-对象,其中包含
错误失败或诸如此类。如果您想获得响应的可能性,您应该只定义一些
响应
协议,但您可能已经知道了。请更具体地说明预期解决方案的所需属性。我基本上想要一个允许JSON解码的类。AuthenticationResponse可以工作,但当返回错误时(成功响应),而当返回错误时(失败响应)我得到一个错误,这是因为从失败响应返回的JSON包含最少的数据,并且显然没有正确映射到AuthenticateResponse@patrui如果您的问题是错误返回,那么您应该不惜一切代价发布产生错误的
JSON
,并尽可能具体地说明错误你得到了。可能
JSONDecoder
会对他得到的东西不满意,你必须在某些点上添加可选项。
switch parse(okData) {
case let .ok(response):
    print(response)
case let .authError(error):
    print(error)
case let .parseError(description):
    print("You threw some garbage at me and I was only able to \(description)")
default:
    print("don't know what to do here")
}