RxSwift 对 Observable 的扩展,其中 Element 是 Result<>

Posted

技术标签:

【中文标题】RxSwift 对 Observable 的扩展,其中 Element 是 Result<>【英文标题】:RxSwift extension to Observable where Element is Result<> 【发布时间】:2021-04-09 19:44:25 【问题描述】:

我有一个返回Observable&lt;Result&lt;Data, APIError&gt;&gt; 的网络请求,我直接将它映射到领域对象的数组中,所以最后我有Observable&lt;Result&lt;[Model], APIError&gt;&gt;,其中Model 符合Decodable 和子类Object

我想为 Observable 编写一个扩展来过滤掉APIError 并发出成功的结果 所以我试着写这样的东西,但它对我不起作用:

extension Observable where Element == Result<[Decodable], APIError> 
 func toSuccesOrEmpty() -> Observable<[Decodable]> 
  return flatMap  (result) -> Observable<[Decodable]> in
   switch result 
    case .success(let data):
     return Observable<[Decodable]>.just(data)
    case .failure:
     return Observable<[Decodable]>.empty()
   
  
 

我是 RxSwift 的新手,我可能会想念一些东西。另外我不想在创建这个 observable 时使用onError,因为我想稍后使用这个错误

【问题讨论】:

你有一个可解码的,但你的样本中没有解码器。数据是 JSON 格式吗? @DanielT。是的,它是 JSON 数据。我的代码与您的代码非常相似,但您确实帮助我意识到我可以在将其解析为模型之前退后一步调用我的函数,并且我不会遇到泛型问题,所以谢谢! 【参考方案1】:

我解决这个问题的方法是首先创建一个正常的函数。由于我们正在处理可解码,这意味着我们想要使用泛型......普通函数不能只是忽略错误,它必须使返回值可选或抛出错误。我在这里选择了后者:

func convertOrThrow<T>(input: Result<Data, APIError>) throws -> T where T: Decodable 
    switch input 
    case .success(let data):
        return try JSONDecoder().decode(T.self, from: data)
    case .failure(let error):
        throw error
    

上面的函数很容易测试。确保它可以正常工作,然后将其包装在 Observable 扩展中,如下所示:

extension ObservableType where Element == Result<Data, APIError> 
    func toSuccesOrEmpty<T>() -> Infallible<T> where T: Decodable 
        map(convertOrThrow(input:))
            .asInfallible(onErrorRecover:  _ in Infallible.empty() )
    

通过返回 Infallible,您断言它不会发出错误。

但是,直接在函数中创建JSONDecoder 感觉不对。我们希望能够传入一个解码器。所以让我们把它变成一个工厂函数:

func convertOrThrow<T>(decoder: JSONDecoder) -> (Result<Data, APIError>) throws -> T where T: Decodable 
     input in
        switch input 
        case .success(let data):
            return try JSONDecoder().decode(T.self, from: data)
        case .failure(let error):
            throw error
        
    

然后通过 Observable 扩展将解码器传入其中...

extension ObservableType where Element == Result<Data, APIError> 
    func toSuccesOrEmpty<T>(decoder: JSONDecoder) -> Infallible<T> where T: Decodable 
        map(convertOrThrow(decoder: decoder))
            .asInfallible(onErrorRecover:  _ in Infallible.empty() )
    

最后,仅在返回值中包含泛型类型可能会很痛苦。这意味着您必须在呼叫站点手动设置类型。让我们以与解码器相同的方式明确这一点,将类型作为参数传递:

extension ObservableType where Element == Result<Data, APIError> 
    func toSuccesOrEmpty<T>(_ type: T.Type, decoder: JSONDecoder) -> Infallible<T> where T: Decodable 
        map(convertOrThrow(type, decoder: decoder))
            .asInfallible(onErrorRecover:  _ in Infallible.empty() )
    


func convertOrThrow<T>(_ type: T.Type, decoder: JSONDecoder) -> (Result<Data, APIError>) throws -> T where T: Decodable 
     input in
        switch input 
        case .success(let data):
            return try JSONDecoder().decode(T.self, from: data)
        case .failure(let error):
            throw error
        
    

你可以这样称呼它:

let myModels = myRequest.toSuccesOrEmpty([Model].self, decoder: JSONDecoder())

【讨论】:

以上是关于RxSwift 对 Observable 的扩展,其中 Element 是 Result<>的主要内容,如果未能解决你的问题,请参考以下文章

用于将 Single<[Element]> 转换为 Observable<Element> 的 rxSwift 扩展

RxSwift 对一个 observable 的多个订阅

在 RxSwift 中,我如何对 observable 未发送任何事件进行单元测试?

rxswift:如何获取 Observable<Any> 导致 Observable<[Category]> 的组合?

如何使用 RxSwift Observable<Int>.interval?

RxSwift:延迟 observable 直到另一个 observable 完成?