RxSwift,分享+重试机制
RxSwift, Share + retry mechanism
我有一个可以成功或失败的网络请求
我已经把它封装在一个observable中了。
我有 2 个请求规则
1) There can never be more then 1 request at the same time
-> there is a share operator i can use for this
2) When the request was Succeeded i don't want to repeat the same
request again and just return the latest value
-> I can use shareReplay(1) operator for this
问题出现在请求失败时,shareReplay(1)只会重放最新的错误,不会重新开始请求。
请求应在下一次订阅时重新开始。
有谁知道我如何将它变成 Observable 链?
// scenario 1
let obs: Observable<Int> = request().shareReplay(1)
// outputs a value
obs.subscribe()
// does not start a new request but outputs the same value as before
obs.subscribe()
// scenario 2 - in case of an error
let obs: Observable<Int> = request().shareReplay(1)
// outputs a error
obs.subscribe()
// does not start a new request but outputs the same value as before, but in this case i want it to start a new request
obs.subscribe()
这似乎正是我想要的,但它包括将状态保持在可观察之外,有人知道我如何以更 Rx 的方式实现这一点吗?
enum Err: Swift.Error {
case x
}
enum Result<T> {
case value(val: T)
case error(err: Swift.Error)
}
func sample() {
var result: Result<Int>? = nil
var i = 0
let intSequence: Observable<Result<Int>> = Observable<Int>.create { observer in
if let result = result {
if case .value(let val) = result {
return Observable<Int>.just(val).subscribe(observer)
}
}
print("do work")
delay(1) {
if i == 0 {
observer.onError(Err.x)
} else {
observer.onNext(1)
observer.onCompleted()
}
i += 1
}
return Disposables.create {}
}
.map { value -> Result<Int> in Result.value(val: value) }
.catchError { error -> Observable<Result<Int>> in
return .just(.error(err: error))
}
.do(onNext: { result = [=11=] })
.share()
_ = intSequence
.debug()
.subscribe()
delay(2) {
_ = intSequence
.debug()
.subscribe()
_ = intSequence
.debug()
.subscribe()
}
delay(4) {
_ = intSequence
.debug()
.subscribe()
}
}
sample()
它仅在我们没有缓存任何内容时生成工作,但同样我们需要使用副作用来实现所需的输出
如果 Observable
序列发出错误,它永远不会发出另一个事件。然而,使用 flatMap
将一个容易出错的 Observable
包裹在另一个 Observable
中并在它们被允许传播到外部 [=11] 之前捕获任何错误是一种相当普遍的做法=].例如:
safeObservable
.flatMap {
Requestor
.makeUnsafeObservable()
.catchErrorJustReturn(0)
}
.shareReplay(1)
.subscribe()
如前所述,RxSwift
错误需要被视为致命错误。它们是您的流通常无法恢复的错误,而且通常是用户不会遇到的错误。
出于这个原因 - 发出 .error
或 .completed
事件的流将立即处理,您不会在那里收到任何更多事件。
有两种方法可以解决这个问题:
- 像刚才一样使用结果类型
- 使用
.materialize()
(如果需要,还可以使用 .dematerialize()
)。这些第一个运算符会将你的 Observable<Element>
变成 Observable<Event<Element>>
,这意味着你将得到一个元素,告诉你这是一个错误事件,但没有任何终止,而不是发出错误和序列终止。
您可以在 Adam Borek 的精彩博客 post 中阅读有关 RxSwift 错误处理的更多信息:http://adamborek.com/how-to-handle-errors-in-rxswift/
我有一个可以成功或失败的网络请求
我已经把它封装在一个observable中了。 我有 2 个请求规则
1) There can never be more then 1 request at the same time
-> there is a share operator i can use for this
2) When the request was Succeeded i don't want to repeat the same request again and just return the latest value
-> I can use shareReplay(1) operator for this
问题出现在请求失败时,shareReplay(1)只会重放最新的错误,不会重新开始请求。
请求应在下一次订阅时重新开始。
有谁知道我如何将它变成 Observable 链?
// scenario 1
let obs: Observable<Int> = request().shareReplay(1)
// outputs a value
obs.subscribe()
// does not start a new request but outputs the same value as before
obs.subscribe()
// scenario 2 - in case of an error
let obs: Observable<Int> = request().shareReplay(1)
// outputs a error
obs.subscribe()
// does not start a new request but outputs the same value as before, but in this case i want it to start a new request
obs.subscribe()
这似乎正是我想要的,但它包括将状态保持在可观察之外,有人知道我如何以更 Rx 的方式实现这一点吗?
enum Err: Swift.Error {
case x
}
enum Result<T> {
case value(val: T)
case error(err: Swift.Error)
}
func sample() {
var result: Result<Int>? = nil
var i = 0
let intSequence: Observable<Result<Int>> = Observable<Int>.create { observer in
if let result = result {
if case .value(let val) = result {
return Observable<Int>.just(val).subscribe(observer)
}
}
print("do work")
delay(1) {
if i == 0 {
observer.onError(Err.x)
} else {
observer.onNext(1)
observer.onCompleted()
}
i += 1
}
return Disposables.create {}
}
.map { value -> Result<Int> in Result.value(val: value) }
.catchError { error -> Observable<Result<Int>> in
return .just(.error(err: error))
}
.do(onNext: { result = [=11=] })
.share()
_ = intSequence
.debug()
.subscribe()
delay(2) {
_ = intSequence
.debug()
.subscribe()
_ = intSequence
.debug()
.subscribe()
}
delay(4) {
_ = intSequence
.debug()
.subscribe()
}
}
sample()
它仅在我们没有缓存任何内容时生成工作,但同样我们需要使用副作用来实现所需的输出
如果 Observable
序列发出错误,它永远不会发出另一个事件。然而,使用 flatMap
将一个容易出错的 Observable
包裹在另一个 Observable
中并在它们被允许传播到外部 [=11] 之前捕获任何错误是一种相当普遍的做法=].例如:
safeObservable
.flatMap {
Requestor
.makeUnsafeObservable()
.catchErrorJustReturn(0)
}
.shareReplay(1)
.subscribe()
如前所述,RxSwift
错误需要被视为致命错误。它们是您的流通常无法恢复的错误,而且通常是用户不会遇到的错误。
出于这个原因 - 发出 .error
或 .completed
事件的流将立即处理,您不会在那里收到任何更多事件。
有两种方法可以解决这个问题:
- 像刚才一样使用结果类型
- 使用
.materialize()
(如果需要,还可以使用.dematerialize()
)。这些第一个运算符会将你的Observable<Element>
变成Observable<Event<Element>>
,这意味着你将得到一个元素,告诉你这是一个错误事件,但没有任何终止,而不是发出错误和序列终止。
您可以在 Adam Borek 的精彩博客 post 中阅读有关 RxSwift 错误处理的更多信息:http://adamborek.com/how-to-handle-errors-in-rxswift/