迅速。结合。重试时有什么方法可以多次调用发布者块?

时间:2019-12-07 09:50:05

标签: swift combine

当我使用Swift / Combine的retry()发生某些错误时,我想发出一个以上的网络请求。发布者内部的块仅被调用一次,这意味着在发生错误时仅对真实应用程序发出一个请求。我的代码是:

import UIKit
import Combine
import PlaygroundSupport

enum TestFailureCondition: Error {
    case invalidServerResponse
}

var backgroundQueue: DispatchQueue = DispatchQueue(label: "backgroundQueue")

var failPublisher: AnyPublisher<(Data, URLResponse), Error> {
    Future<(Data, URLResponse), Error> { promise in
        print("Attempt to call")
        backgroundQueue.asyncAfter(deadline: .now() + Double.random(in: 1..<3)) {
            promise(.failure(TestFailureCondition.invalidServerResponse))
        }
    }
    .eraseToAnyPublisher()
}

let cancellable = failPublisher
.print("(1)>")
.retry(3)
.print("(2)>")
.sink(receiveCompletion: { fini in
    print(" ** .sink() received the completion:", String(describing: fini))


    PlaygroundPage.current.finishExecution()
}, receiveValue: { stringValue in
    print(" ** .sink() received \(stringValue)")
})

PlaygroundPage.current.needsIndefiniteExecution = true

我希望backgroundQueue.asyncAfter(deadline)在发生某些错误之前被调用三遍。有人知道为什么吗?

2 个答案:

答案 0 :(得分:1)

Future一旦创建,便会运行一次它的主体,即使没有订阅它。它保存结果并用相同的结果完成所有订阅。因此,在retry上使用Future运算符不会使Future在失败时再次运行其主体。

您希望每个订阅再次运行主体。您可以通过将Future包装在Deferred中来实现。 Deferred将为每个订阅创建一个新的Future

var failPublisher: AnyPublisher<(Data, URLResponse), Error> {
    Deferred {
        Future<(Data, URLResponse), Error> { promise in
            print("Attempt to call")
            backgroundQueue.asyncAfter(deadline: .now() + Double.random(in: 1..<3)) {
                promise(.failure(TestFailureCondition.invalidServerResponse))
            }
        }
    }
    .eraseToAnyPublisher()
}

答案 1 :(得分:0)

我通过利用tryCatch()函数并提出了另一个请求:Link

来实现了预期的行为

该链接包含两种实现相同行为的方式,包括上述Deferred {}