如何立即触发 Timer.publish()?

Sen*_*ful 4 swift combine

通过组合创建了一个计时器,Date使用以下代码发出和忽略错误:

let timer: AnyPublisher<Date, Never> = Timer.publish(every: 5, on: .main, in: RunLoop.Mode.common)
  .autoconnect()
  .map { _ in Date() }
  .replaceError(with: Date())
  .eraseToAnyPublisher()
Run Code Online (Sandbox Code Playgroud)

(我确信有比映射和替换错误更好的方法,但对于这个例子,我想保持类型简单,AnyPublisher<Date, Never>.)

计时器正确触发,但从创建计时器到第一次触发(即等待 5 秒)之间存在延迟。使用NSTimer,我们可以调用 timer.fire()来强制它立即触发。

是否有等效的方法来强制计时器在使用时立即发布Timer.publish()


或者,有没有办法Just(Date())与上述合并,Timer.publish以便它立即每 5 秒触发一次,同时仍然保持AnyPublisher<Date, Never>类型?

小智 14

另外,还有一个使用prepend 的选项

let delayPublisher = Timer.publish(every: 5, on: .main, in: .common)
  .autoconnect()
  .receive(on: RunLoop.main)
  .prepend(Date())
Run Code Online (Sandbox Code Playgroud)

  • 我认为迄今为止最简单的解决方案,当您只需添加初始值时不需要与另一个发布者合并 (4认同)

rob*_*off 8

我确信有比映射和替换错误更好的方法

Timer.TimerPublisher.Failureis Never,因此您不需要任何映射,因为它不会失败。

此外,Timer.TimerPublisher.Output已经是当前的Date(),所以你也不需要map输出。

要在订阅时立即发出当前日期,您需要将 aDeferred { Just(Date()) }与计时器发布者结合起来。这Deferred意味着在订阅发生之前不会计算当前日期。

这是将所有内容放在一起的一种方法:

let timer = Deferred { Just(Date()) }
    .append(Timer.publish(every: 5, on: .main, in: .common).autoconnect())
    .eraseToAnyPublisher()
Run Code Online (Sandbox Code Playgroud)


Mar*_*ñuk 6

除了 @rob mayoff 答案和 @Senseful 评论,可以合并计时器执行的“第一个值”:

let delayPublisher = Timer.publish(every: 5, on: .main, in: .common)
  .autoconnect()
  .receive(on: RunLoop.main)
  .merge(with: Just(Date()))
Run Code Online (Sandbox Code Playgroud)