如何从失败的接收链中恢复?
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您应该使用
Catch
方法< /a> 来处理错误,您可以使用它们来阻止序列在发生错误事件时终止。一个忽略任何错误的简单示例是,每当您的
getParamterDefinition
observable 发出错误时,就返回 nil: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: