如何在 ios 应用程序中重试具有时间延迟的失败 Web 服务调用
How to retry failed web service calls with time delay in ios app
我正在开发一个 IOS 应用程序,根据要求,我需要重试所有失败的 api 3 次,延迟 3 秒。为此,我按如下方式向 Publisher 添加了一个扩展,但此代码存在一个小问题,在最后一次尝试之后,如果我收到失败的响应,则需要 3 秒才能执行预期的失败代码。我需要在上次尝试失败后立即显示失败消息,有什么办法可以解决这个问题吗?
public extension Publisher {
func retryWithDelay<S>(
retries: Int,
delay: S.SchedulerTimeType.Stride,
scheduler: S
) -> AnyPublisher<Output, Failure> where S: Scheduler {
self
.delayIfFailure(for: delay, scheduler: scheduler)
.retry(retries)
.eraseToAnyPublisher()
}
private func delayIfFailure<S>(
for delay: S.SchedulerTimeType.Stride,
scheduler: S
) -> AnyPublisher<Output, Failure> where S: Scheduler {
self.catch { error in
Future { completion in
scheduler.schedule(after: scheduler.now.advanced(by: delay)) {
completion(.failure(error))
}
}
}
.eraseToAnyPublisher()
}
}
最好创建一个自定义 Publisher
,其想法是您可以跟踪失败的次数,并且 return 延迟发布者(失败)在正常情况下,或最后一次重试的非延迟发布者。
struct RetryWithDelay<Upstream: Publisher, S: Scheduler>: Publisher {
typealias Output = Upstream.Output
typealias Failure = Upstream.Failure
let upstream: Upstream
let retries: Int
let interval: S.SchedulerTimeType.Stride
let scheduler: S
func receive<Sub>(subscriber: Sub)
where Sub : Subscriber,
Upstream.Failure == Sub.Failure,
Upstream.Output == Sub.Input {
var retries = self.retries
let p = upstream
.catch { err -> AnyPublisher<Output, Failure> in
retries -= 1
return Fail(error: err)
.delay(for: retries > 0 ? interval : .zero, scheduler: scheduler)
.eraseToAnyPublisher()
}
.retry(self.retries)
p.subscribe(subscriber)
}
}
为方便起见,您可以创建一个运算符,就像您在问题中所做的那样:
public extension Publisher {
func retryWithDelay<S>(
retries: Int,
delay: S.SchedulerTimeType.Stride,
scheduler: S
) -> RetryWithDelay<Self, S> where S: Scheduler {
RetryWithDelay(upstream: self,
retries: retries, delay: delay, scheduler: scheduler)
}
}
我正在开发一个 IOS 应用程序,根据要求,我需要重试所有失败的 api 3 次,延迟 3 秒。为此,我按如下方式向 Publisher 添加了一个扩展,但此代码存在一个小问题,在最后一次尝试之后,如果我收到失败的响应,则需要 3 秒才能执行预期的失败代码。我需要在上次尝试失败后立即显示失败消息,有什么办法可以解决这个问题吗?
public extension Publisher {
func retryWithDelay<S>(
retries: Int,
delay: S.SchedulerTimeType.Stride,
scheduler: S
) -> AnyPublisher<Output, Failure> where S: Scheduler {
self
.delayIfFailure(for: delay, scheduler: scheduler)
.retry(retries)
.eraseToAnyPublisher()
}
private func delayIfFailure<S>(
for delay: S.SchedulerTimeType.Stride,
scheduler: S
) -> AnyPublisher<Output, Failure> where S: Scheduler {
self.catch { error in
Future { completion in
scheduler.schedule(after: scheduler.now.advanced(by: delay)) {
completion(.failure(error))
}
}
}
.eraseToAnyPublisher()
}
}
最好创建一个自定义 Publisher
,其想法是您可以跟踪失败的次数,并且 return 延迟发布者(失败)在正常情况下,或最后一次重试的非延迟发布者。
struct RetryWithDelay<Upstream: Publisher, S: Scheduler>: Publisher {
typealias Output = Upstream.Output
typealias Failure = Upstream.Failure
let upstream: Upstream
let retries: Int
let interval: S.SchedulerTimeType.Stride
let scheduler: S
func receive<Sub>(subscriber: Sub)
where Sub : Subscriber,
Upstream.Failure == Sub.Failure,
Upstream.Output == Sub.Input {
var retries = self.retries
let p = upstream
.catch { err -> AnyPublisher<Output, Failure> in
retries -= 1
return Fail(error: err)
.delay(for: retries > 0 ? interval : .zero, scheduler: scheduler)
.eraseToAnyPublisher()
}
.retry(self.retries)
p.subscribe(subscriber)
}
}
为方便起见,您可以创建一个运算符,就像您在问题中所做的那样:
public extension Publisher {
func retryWithDelay<S>(
retries: Int,
delay: S.SchedulerTimeType.Stride,
scheduler: S
) -> RetryWithDelay<Self, S> where S: Scheduler {
RetryWithDelay(upstream: self,
retries: retries, delay: delay, scheduler: scheduler)
}
}