如何从失败的接收链中恢复?

发布于 2025-01-09 09:44:49 字数 3123 浏览 1 评论 0原文

Rx 似乎有点脆弱,因为如果一件事不起作用,它就会关闭整个链条。这已经成为我的代码中的一个真正问题,因为我有一个通过 ble 请求参数的链。首先我们请求 ids,然后是definitions,它是一种映射最小值和最大值的方式,最后它请求实际的parameters

override func getParameters() -> Single<[ParameterModel?]> {
    parameterCounter = 0
    parameterDefinitionCounter = 0
    
    return getParamterIds().do(onSuccess: { [weak self] values in
        self?.numberOfParameterIds = Float(values?.count ?? 0)
    })
        .flatMap { ids in
            Single.zip(ids!.compactMap { self.getParamterDefinition(id: $0) }) }
        .flatMap { parameters in
            Single.zip(parameters.compactMap { self.getParameter(id: $0!.id) }) }
}

所以如果我们获取一个包含 30 个参数 id 的数组,它会进入 getParamterDefinition(id: $0) 中。如果其中一个失败(确实如此),整个事情就会关闭,并且 self.getParameter(id: $0!.id) 永远不会运行。因此,即使 29 个参数通过 getParamterDefinition(id: $0) 传递,也没有任何内容传递给 self.getParameter(id: $0!.id)。

如何从错误中恢复并继续在链中运行,以便将 getParamterDefinition(id: $0) 中成功的内容传递给 self.getParameter(id: $0!.id) 并显示给用户?

*** 更新 *** 对于有兴趣解决此类问题的任何人来说,这是最终结果:

override func getParameters() -> Single<[ParameterModel?]> {
        parameterCounter = 0
        parameterDefinitionCounter = 0
        
        func getFailedParameter(id: Int) -> ParameterModel {
            return ParameterModel(id: id, name: String(format: "tech_app_failed_getting_parameter".localized(), "\(id)"), min: 2000,
                                  max: 21600000, defaultValue: 2500, value: 2500,
                                  unit: "ms", access: 0, freezeFlag: 0,
                                  multiplicator: 1, operatorByte: 1, brand: 0,
                                  states: nil, didFailRetrievingParameter: true)
        }
        
        return getParamterIds().do(onSuccess: { [weak self] values in
            self?.numberOfParameterIds = Float(values?.count ?? 0)
        }).catchError { _ in return Single.just([]) }
            .flatMap { ids in
                Single.zip(ids!.compactMap { id in
                    self.getParamterDefinition(id: id).catchError { [weak self] _ in
                        self?.parameterErrorStatusRelay.accept(String(format: "tech_app_parameter_definition_error_status".localized(), "\(id)"))
                        return Single.just(getFailedParameter(id: id))
                    }
                })
            }
            .flatMap { parameters in
                Single.zip(parameters.compactMap { parameter in
                    guard let parameter = parameter, !(parameter.didFailRetrievingParameter) else {
                        return Single.just(parameter)
                    }
                    
                    return self.getParameter(id: parameter.id).catchError { [weak self] _ in
                        self?.parameterErrorStatusRelay.accept(String(format: "tech_app_parameter_error_status".localized(), "\(parameter.id)"))
                        return Single.just(getFailedParameter(id: parameter.id))
                    }
                })
            }
    }

Rx seem a bit fragile in that it closes down an entire chain if one single thing doesn't work. That has become a real problem in my code as I have a chain that requests parameters through ble. First we ask for ids, then definitions which is sort of mapping min and max values, lastly it asks for the actual parameters:

override func getParameters() -> Single<[ParameterModel?]> {
    parameterCounter = 0
    parameterDefinitionCounter = 0
    
    return getParamterIds().do(onSuccess: { [weak self] values in
        self?.numberOfParameterIds = Float(values?.count ?? 0)
    })
        .flatMap { ids in
            Single.zip(ids!.compactMap { self.getParamterDefinition(id: $0) }) }
        .flatMap { parameters in
            Single.zip(parameters.compactMap { self.getParameter(id: $0!.id) }) }
}

So if we get an array with 30 parameter ids, it goes into getParamterDefinition(id: $0). And if it fails on a single one of those, which it does, the whole thing closes down and self.getParameter(id: $0!.id) is never run. So even though 29 parameters pass through getParamterDefinition(id: $0) nothing is passed to self.getParameter(id: $0!.id).

How do I recover from an error and keep going in the chain so that those that were successful in getParamterDefinition(id: $0) gets passed to self.getParameter(id: $0!.id) and gets displayed to the user?

*** UPDATE ***
This is the final result for anyone interested in solving issues like these:

override func getParameters() -> Single<[ParameterModel?]> {
        parameterCounter = 0
        parameterDefinitionCounter = 0
        
        func getFailedParameter(id: Int) -> ParameterModel {
            return ParameterModel(id: id, name: String(format: "tech_app_failed_getting_parameter".localized(), "\(id)"), min: 2000,
                                  max: 21600000, defaultValue: 2500, value: 2500,
                                  unit: "ms", access: 0, freezeFlag: 0,
                                  multiplicator: 1, operatorByte: 1, brand: 0,
                                  states: nil, didFailRetrievingParameter: true)
        }
        
        return getParamterIds().do(onSuccess: { [weak self] values in
            self?.numberOfParameterIds = Float(values?.count ?? 0)
        }).catchError { _ in return Single.just([]) }
            .flatMap { ids in
                Single.zip(ids!.compactMap { id in
                    self.getParamterDefinition(id: id).catchError { [weak self] _ in
                        self?.parameterErrorStatusRelay.accept(String(format: "tech_app_parameter_definition_error_status".localized(), "\(id)"))
                        return Single.just(getFailedParameter(id: id))
                    }
                })
            }
            .flatMap { parameters in
                Single.zip(parameters.compactMap { parameter in
                    guard let parameter = parameter, !(parameter.didFailRetrievingParameter) else {
                        return Single.just(parameter)
                    }
                    
                    return self.getParameter(id: parameter.id).catchError { [weak self] _ in
                        self?.parameterErrorStatusRelay.accept(String(format: "tech_app_parameter_error_status".localized(), "\(parameter.id)"))
                        return Single.just(getFailedParameter(id: parameter.id))
                    }
                })
            }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

薆情海 2025-01-16 09:44:49

您应该使用 Catch 方法< /a> 来处理错误,您可以使用它们来阻止序列在发生错误事件时终止。

一个忽略任何错误的简单示例是,每当您的 getParamterDefinition observable 发出错误时,就返回 nil:

override func getParameters() -> Single<[ParameterModel?]> {
    return getParameterIds()
        .do(onSuccess: { [weak self] values in
            self?.numberOfParameterIds = Float(values?.count ?? 0)
        })
        .flatMap { ids in
            Single.zip(
                ids!.compactMap {
                    self.getParameterDefinition(id: $0)?
                        .catchAndReturn(nil)
                }
            )
        }
        .flatMap { parameters in
            Single.zip(
                parameters.compactMap { parameter in
                    parameter.flatMap { self.getParameter(id: $0.id) }
                }
            )
        }
}

You should use the Catch methods to handle errors, you can use these to stop your sequence from terminating when an error event occurs.

A simple example that just ignores any errors would be to return nil whenever your getParamterDefinition observable emits an error:

override func getParameters() -> Single<[ParameterModel?]> {
    return getParameterIds()
        .do(onSuccess: { [weak self] values in
            self?.numberOfParameterIds = Float(values?.count ?? 0)
        })
        .flatMap { ids in
            Single.zip(
                ids!.compactMap {
                    self.getParameterDefinition(id: $0)?
                        .catchAndReturn(nil)
                }
            )
        }
        .flatMap { parameters in
            Single.zip(
                parameters.compactMap { parameter in
                    parameter.flatMap { self.getParameter(id: $0.id) }
                }
            )
        }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文