迅速。结合。有没有办法在重试时多次调用发布者块?

Dmi*_*try 9 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
Run Code Online (Sandbox Code Playgroud)

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

rob*_*off 13

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

您希望每个订阅再次运行正文。您可以通过将您FutureDeferred. 该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()
}
Run Code Online (Sandbox Code Playgroud)


Dmi*_*try 3

我设法通过利用tryCatch()功能并提出另一个请求来实现预期的行为:链接

该链接包含两种实现相同行为的方法,包括Deferred {}上面提到的。