【问题标题】:Swift Combine - delaying a publisherSwift Combine - 延迟发布者
【发布时间】:2020-04-05 01:45:44
【问题描述】:

TL;DR

我想推迟发布,但不知道如何,呃,合并部分

简介

我有一个Publisher

let generator = PassthroughSubject<Bool, Never>()

并且想以某种方式使用修饰符

.delay(for: 2, scheduler: RunLoop.main)

这样当我打电话时

generator.send(true)

消息在呼叫send()后两秒发送

查看Publishers.Delay 的文档使类型错误更加清晰,但并不能帮助我找到正确的连接方式。

代码

import SwiftUI
import Combine

// Exists just to subscribe.
struct ContainedView : View {
    private let publisher: AnyPublisher<Bool, Never>
    init(_ publisher: AnyPublisher<Bool, Never> = Just(false).dropFirst().eraseToAnyPublisher()) {
        self.publisher = publisher
    }
    var body: some View {
        Rectangle().onReceive(publisher) { _ in print("Got it") }
    }
}

struct ContentView: View {
    let generator = PassthroughSubject<Bool, Never>()
                 // .delay(for: 2, scheduler: RunLoop.main)
                 // Putting it here doesn't work either.

    var body: some View {
        VStack {
            Button("Tap") {

                // Does not compile
                self.generator.delay(for: 2, scheduler: RunLoop.main).send(true)
                // Value of type 'Publishers.Delay<PassthroughSubject<Bool, Never>, RunLoop>' has no member 'send'
                // https://developer.apple.com/documentation/combine/publishers/delay

                // Does not compile
                self.generator.send(true).delay(for: 2, scheduler: RunLoop.main)
                // Value of tuple type '()' has no member 'delay'

                // Just a broken-up version of the first try.
                let delayed = self.generator.delay(for: 2, scheduler: RunLoop.main)
                delayed.send(true)

                // This, of course, builds and works.
                self.generator.send(true)
                print("Sent it")
            }

            ContainedView(generator.eraseToAnyPublisher())
            .frame(width: 300, height: 200)
        }
    }
}

【问题讨论】:

    标签: delay publish-subscribe combine


    【解决方案1】:

    您可以使用发布者的 debounce 属性来延迟发布。

    $yourProperty
        .debounce(for: 0.8, scheduler: RunLoop.main)
        .eraseToAnyPublisher()
    

    【讨论】:

      【解决方案2】:

      .delay(for: 2, scheduler: RunLoop.main) 可能正是您所需要的,但关键是要了解您如何订阅才能完全理解该问题。当使用 send() 和主题时,延迟不会延迟值的发送 - 这是命令式代码的链接,只要调用 send 就会发送数据,通常针对一些已经存在的订阅。

      虽然您在第一段代码中有订阅者,但没有一个主题可以将它们固定在一起。

      例如,如果您更新了:

      Just(false).dropFirst().eraseToAnyPublisher()

      到

      Just(false).dropFirst().eraseToAnyPublisher().delay(for: 2, scheduler: RunLoop.main)

      然后 print 语句应该在调用 init() 后约 2 秒触发。根据您在此处尝试完成的任务,使用onAppear 之类的关闭触发器可能更有意义,调用subject.send(),然后您可以在之前发生的发布者链中随意延迟订阅它的任何东西。

      【讨论】:

      • 谢谢@heckj,我确实觉得,每次我使用send() 时,我都过于迫切了,如果-this-then-that,而不是基于状态的生活-现在。
      【解决方案3】:
      var cancellables: [AnyCancellable] = []
      let generator = PassthroughSubject<Bool, Never>()
      let generated = generator.delay(for: 2, scheduler: RunLoop.main).sink { value in
          print(value.description + " " + Date().timeIntervalSinceReferenceDate.description)
      }
      print(Date().timeIntervalSinceReferenceDate.description)
      generator.send(true)
      generator.send(false)
      

      输出

      641453284.840604
      true 641453286.841731
      false 641453286.847715
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-08
        • 2021-07-10
        • 2020-11-06
        • 1970-01-01
        相关资源
        最近更新 更多