jjzjj

swift - 可解码返回对象

coder 2023-09-16 原文

我有一个可解码类:

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
}

在我的错误类中:

为了解码到这个类,我有:

 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()

因为我收到的一些响应是(成功响应):

{
“status”: “SUCCESS”  “error”: null,  "access_token":
"MWVmOWQxMDYwMjQyNDQ4NzQyNTdkZjQ3NmI4YmVjMGZjZGM5N2IyZmNkOTA1 N2M0NDUzODEwYjM5ZWQyNGNkZg",
"expires_in": 3600, "token_type": "bearer", "scope": null, 
"refresh_token":
"ZGEwOGZiOWZhMzhhYjBmMzAyOGRmZTA5NjJhMjY2MTk3YzMyMmE1ZDlkNWI2N mJjYmIxMjNkMjE1NWFhNWY0Mg"
}

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

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

有谁知道我应该怎么做>

最佳答案

我会试一试尝试,但首先我们需要理清我认为有点粗制滥造的问题。由于 Error 是(著名且广泛使用的)协议(protocol) 的名称,因此应该重命名它,并且您希望能够在 AuthenticationResponse<> 它显然必须是一个可选的(问题是为什么它在 Response 中,但我将把它放在一边)。这给我们留下了以下内容:

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

Playground 中的所有这些都将允许使用

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 函数的类型,并通过 throwing 一些 enum(符合 Error)和一些合适的方法来提供其余部分有效负载。

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

无论如何,这为您提供了一个函数来解析您的服务回复的任何一种情况,并以一种“统一”的方式处理它们。由于您可能无法修改处理您的请求 的服务的行为,这可能是唯一可行的选择。但是,如果您能够修改服务,您应该努力获得“统一”的回复,只需调用一次 JSONDecoder.decode 即可解析该回复。你仍然需要解释可选值(就像你在上面的例子中应该做的那样,因为使用它们仍然很痛苦,即使 Swifts 出色的编译器支持迫使你“做正确的事”),但它会使你的解析不易出错。

关于swift - 可解码返回对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47885117/

有关swift - 可解码返回对象的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  3. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  4. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  5. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  6. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  7. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

  8. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  9. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  10. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

随机推荐