如何从失败的 rx 链中恢复?

How do I recover from a failed rx chain?

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: [=10=]) }) }
        .flatMap { parameters in
            Single.zip(parameters.compactMap { self.getParameter(id: [=10=]!.id) }) }
}

所以如果我们得到一个 array 和 30 parameter ids,它进入 getParamterDefinition(id: [=18=])。如果它在其中一个失败了,它确实如此,整个事情就会结束并且 self.getParameter(id: [=19=]!.id) 永远不会 运行。所以即使 29 parameters 通过 getParamterDefinition(id: [=18=]) 也没有任何东西传递给 self.getParameter(id: [=19=]!.id).

如何从错误中恢复并在链中继续前进,以便将在 getParamterDefinition(id: [=18=]) 中成功的错误传递给 self.getParameter(id: [=19=]!.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))
                    }
                })
            }
    }

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

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

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: [=10=])?
                        .catchAndReturn(nil)
                }
            )
        }
        .flatMap { parameters in
            Single.zip(
                parameters.compactMap { parameter in
                    parameter.flatMap { self.getParameter(id: [=10=].id) }
                }
            )
        }
}