ios - 处理 RxSwift 重试和错误处理的最佳实践是什么

标签 ios swift error-handling rx-swift

我读过一些帖子说处理 RxSwift 的最佳实践是只将 fatal error 传递给 onError 并将结果传递给 onNext。

这对我来说很有意义,直到我意识到我无法再处理重试,因为它只发生在 onError 上。

我该如何处理这个问题?

另一个问题是,如何同时处理全局和本地重试混合?

例如,iOS 收据验证流程。

1、尝试在本地获取收据

2、如果失败,向苹果服务器索取最新收据。

3、将收据发送到我们的后台进行验证。

4、如果成功,则整个流程完成

5、如果失败,检查错误码是否可重试,然后返回1。

而在新的 1 中,它会强制从苹果服务器请求新的收据。然后当它再次达到 5 时,整个流程将停止,因为这已经是第二次尝试了。意味着只重试一次。

所以在这个例子中,如果使用状态机而不使用 rx,我将最终使用状态机并共享一些全局状态,如 isSecondAttempt: BoolshouldForceFetchReceipt: Bool

我如何在 rx 中设计这个流程?这些全局共享状态是在流程中设计的。

最佳答案

I read some post says that the best practice to deal with RxSwift is to only pass fatal error to the onError and pass Result to the 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
                }
        }
}

下面是上面使用的支持函数:

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) }
}

关于ios - 处理 RxSwift 重试和错误处理的最佳实践是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54762921/

相关文章:

iphone - Swift/UI Builder 中的编程分页导航

ios - 仅当 indexPath 对象可用时如何在 tableview 单元格上使用标签

templates - 503型错误页面表达式引擎

php - CakePHP 3 - 捕获错误

haskell - Haskell中Either和Except在用法上有什么区别?

ios - 具有自动布局的 UITableViewCell 子类如何在运行时更改约束优先级

ios - 最大化并发 http 下载的数量

swift - 具有相同关联类型名称的协议(protocol)

ios - SKMaps bringToFrontAnnotation : method is working wrong

ios - 传送 iOS 应用程序更新时出错。 "This bundle is invalid. Apple is not currently accepting applications built with this version of the SDK."