问题描述
我看到如何直接使用 .retry
来在出现错误后重新订阅,如下所示:
I see how to use .retry
directly, to resubscribe after an error, like this:
URLSession.shared.dataTaskPublisher(for:url)
.retry(3)
但是,这似乎很简单.如果我认为如果我稍等一下,该错误可能会消失怎么办?我可以插入 .delay
运算符,但是即使没有错误,延迟也会起作用.而且似乎没有办法有条件地应用运算符(即仅在出现错误时).
But that seems awfully simple-minded. What if I think that this error might go away if I wait awhile? I could insert a .delay
operator, but then the delay operates even if there is no error. And there doesn't seem to be a way to apply an operator conditionally (i.e. only when there's an error).
我了解了如何通过从头开始编写RetryWithDelay运算符来解决此问题,实际上,这种运算符已由第三方编写.但是,有一种方法可以纯粹使用我们得到的运算符说如果有错误则延迟"吗?
I see how I could work around this by writing a RetryWithDelay operator from scratch, and indeed such an operator has been written by third parties. But is there a way to say "delay if there's an error", purely using the operators we're given?
我的想法是我可以使用 .catch
,因为它的功能仅在出现错误时运行.但是该函数需要返回一个发布者,我们将使用哪个发布者?如果我们返回 somePublisher.delay(...)
后跟 .retry
,则将 .retry
应用于错误的发布者,不是吗?
My thought was that I could use .catch
, because its function runs only if there is an error. But the function needs to return a publisher, and what publisher would we use? If we return somePublisher.delay(...)
followed by .retry
, we'd be applying .retry
to the wrong publisher, wouldn't we?
推荐答案
这是使用组合项目回购了一段时间-整个线程: https://github.com/heckj/swiftui-notes/issues/164 .
It was a topic of conversation on the Using Combine project repo a while back - the whole thread: https://github.com/heckj/swiftui-notes/issues/164.
总之,我们做了一个例子,尽管它确实使用了 catch
:
The long and short was we made an example that I think does what you want, although it does use catch
:
let resultPublisher = upstreamPublisher.catch { error -> AnyPublisher<String, Error> in
return Publishers.Delay(upstream: upstreamPublisher,
interval: 3,
tolerance: 1,
scheduler: DispatchQueue.global())
// moving retry into this block reduces the number of duplicate requests
// In effect, there's the original request, and the `retry(2)` here will operate
// two additional retries on the otherwise one-shot publisher that is initiated with
// the `Publishers.Delay()` just above. Just starting this publisher with delay makes
// an additional request, so the total number of requests ends up being 4 (assuming all
// fail). However, no delay is introduced in this sequence if the original request
// is successful.
.retry(2)
.eraseToAnyPublisher()
}
这是指我在书/在线版本中使用的重试模式,这基本上就是您所描述的(但不是您所询问的).
This is referencing the a retry pattern I have in the book/online, which is basically what you describe (but wasn't what you asked about).
我在此问题上与之对应的人在该线程中提供了一个变体作为扩展,可能很有趣以及:
The person I was corresponding with on the issue provided a variant in that thread as an extension that might be interesting as well:
extension Publisher {
func retryWithDelay<T, E>()
-> Publishers.Catch<Self, AnyPublisher<T, E>> where T == Self.Output, E == Self.Failure
{
return self.catch { error -> AnyPublisher<T, E> in
return Publishers.Delay(
upstream: self,
interval: 3,
tolerance: 1,
scheduler: DispatchQueue.global()).retry(2).eraseToAnyPublisher()
}
}
}
这篇关于延迟后是否合并框架重试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!