Ton*_*Lin 5 error-handling ios swift rx-swift
我读过一些帖子说处理 RxSwift 的最佳实践是只将致命错误传递给 onError 并将结果传递给 onNext。
这对我来说很有意义,直到我意识到我无法再处理重试,因为它只发生在 onError 上。
我该如何处理这个问题?
另一个问题是,如何同时处理全局和本地重试混合?
例如,iOS 收据验证流程。
1、尝试在本地取收据
2、如果失败,请向苹果服务器索取最新的收据。
3,将收据发送到我们的后端进行验证。
4、如果成功,则整个流程完成
5、如果失败,检查错误代码是否可重试,然后返回1。
而在新的 1 中,它将强制要求从苹果服务器获取新收据。然后当它再次达到 5 时,整个流程将停止,因为这已经是第二次尝试了。意思是只重试一次。
因此,在这个例子中,如果使用状态机,并且不使用RX,我会最终使用状态机和共享一些全局状态一样isSecondAttempt: Bool,shouldForceFetchReceipt: Bool等等。
我如何在 rx 中设计这个流程?与这些在流程中设计的全局共享状态。
我读到一些帖子说处理 RxSwift 的最佳实践是只将致命错误传递给 onError 并将 Result 传递给 onNext。
我不同意这种观点。onError它基本上是说,只有当程序员犯了错误时才应该使用。您应该使用错误来处理不愉快的路径或中止过程。它们就像投掷一样,只是以异步方式进行。
这是作为 Rx 链的算法。
enum ReceiptError: Error {
case noReceipt
case tooManyAttempts
}
struct Response {
// the server response info
}
func getReceiptResonse() -> Observable<Response> {
return fetchReceiptLocally()
.catchError { _ in askAppleForReceipt() }
.flatMapLatest { data in
sendReceiptToServer(data)
}
.retryWhen { error in
error
.scan(0) { attempts, error in
let max = 1
guard attempts < max else { throw ReceiptError.tooManyAttempts }
guard isRetryable(error) else { throw error }
return attempts + 1
}
}
}
Run Code Online (Sandbox Code Playgroud)
以下是上面使用的支持功能:
func fetchReceiptLocally() -> Observable<Data> {
// return the local receipt data or call `onError`
}
func sendReceiptToServer(_ data: Data) -> Observable<Response> {
// send the receipt data or `onError` if the server failed to receive or process it correctly.
}
func isRetryable(_ error: Error) -> Bool {
// is this error the kind that can be retried?
}
func askAppleForReceipt() -> Observable<Data> {
return Observable.just(Bundle.main.appStoreReceiptURL)
.map { (url) -> URL in
guard let url = url else { throw ReceiptError.noReceipt }
return url
}
.observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.map { try Data(contentsOf: $0) }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3449 次 |
| 最近记录: |