Combine - 延迟发布者的发送

Combine - Delay publisher's send

什么是最好的方法来延迟发布者在 Swift Combine 中发送一些数据的时间?让我们假设以下情况:

private var publisher: PassthroughSubject<Progress, Error>

// closure called every second:
startWithProgress() { [weak self] progress in
    self.publisher.send(.init(progress: progress))

    // How to call this 0.5 second after the above `send`:
    self.publisher.send(.init(progress: progress + 0.5))
}

我检查了 Delay API,但似乎我需要创建另一个发布者才能使用它,这对我来说不是最佳选择。我还检查了 throttledebounce,但它们也不允许我一个接一个地发送 2 个更新,它们之间有给定的延迟。

看你分享的,我不会用Combine。 DispatchQueue.asyncAfter(deadline:execute:) 好像够了。

话虽这么说,但如果必须的话,可以使用 Publisher.delay(for:tolerance:scheduler:options:) :

let subject = PassthroughSubject<Progress, Error>()
subject.delay(for: .seconds(5), scheduler: RunLoop.main)
    .replaceError(with: .init())
    .sink { progress in
        self.publisher.send(.init(progress: progress + 0.5))
    }
    .store(in: &cancellables)

甚至Publisher.publish(every:tolerance:on:in:options:)

Timer
    .publish(every: 5, on: .main, in: .default)
    .autoconnect()
    .first()
    .sink { _ in
        self.publisher.send(.init(progress: progress + 0.5))
    }

或者,如果对您的情况有意义,在 @Published 变量中包含 progress 并使用它来启动管道

我还没有测试过,使用计时器可能更有意义。您需要将 cancelable 存储在一个实例变量中,这样它就不会在函数 returns.

时消失
var cancellable = self.publisher
    .delay(for: .seconds(0.5), scheduler: RunLoop.main )
    .sink(receiveCompletion:{ _ in
    // do something with the error or completion
}, receiveValue:{ [unowned self] progress in
        // you don't show any code that actually updates progress, without that this will just keep sending the initial value + 0.5.
        self.publisher.send(.init(progress: progress + 0.5))
    })
self.publisher.send(.init(progress: progress))

延迟发送值的行为(您可以使用 DispatchQueue.asyncAfter 执行)与创建延迟上游值的组合管道之间存在差异。

您没有详细说明您实际要完成的任务,因此很难给出明确的答案。

如果我概括地说,您似乎想要一个管道,它为每个上游值发出值,然后再次发出值 + 0.5,但延迟。这可以像下面这样完成,例如:

let duplicateAndDelay = publisher
   .flatMap { [([=10=], 0), ([=10=] + 0.5, 0.5)].publisher } // duplicate
   .flatMap { (progress, delay) in 
      Just(progress)
         .delay(for: .seconds(delay), scheduler: RunLoop.main) // delay
   }

那么你可以 send 一次:

startWithProgress() { [weak self] progress in
   self?.publisher.send(progress)
}

和return要订阅的duplicateAndDelay发布者,而不是publisher发布者。