【问题标题】:Make sure subscribe (sink) happens only once确保订阅(接收器)只发生一次
【发布时间】:2021-03-16 14:48:57
【问题描述】:

我正在尝试编写一个“类似闭包”的组合观察者。 假设我有 MyClass

class MyClass {
    @Published var value: Int = 0

    func doSomethingClosure(completion: (Int?) -> Void) {
        value += 1
        completion(value)
    }

    func doSomethingCombine() {
        value += 1
    }
}

我可以使用带有闭包的简单函数来访问它

let myClass = MyClass()
myClass.doSomethingClosure { (value) in
    print(value)
}

现在,我想使用组合 @Published 来做同样的事情 所以我会打电话

var cancelSet: Set<AnyCancellable> = []
myClass.$value
    .sink { (value) in
    print(value)
}.store(in: &cancelSet)

但是,我希望它只触发一次,所以如果我调用

for _ in 0..<5 {
    myClass.doSomethingCombine()
}

我不会得到 5 个打印件,而只会得到第一个。 我为此找到的一种解决方案是取消接收器内的订阅者:

myClass.$value
    .sink { (value) in
    print(value)
    **cancelSet.removeAll()**
}.store(in: &cancelSet)

但我觉得它有点“不像预期的那样”。

另一种解决方案是使用背压的方法,例如:

class MySubscriber: Subscriber {
    typealias Input = Int
    typealias Failure = Never
    
    func receive(subscription: Subscription) {
        subscription.request(.max(1))
    }
    
    func receive(completion: Subscribers.Completion<Never>) {
        print("Subscription \(completion)")
    }
    
    func receive(_ input: Int) -> Subscribers.Demand {
        print("Input:\(input)")
        return .none
    }
}
let mySubscriber = MySubscriber()
myClass.$value.subscribe(mySubscriber)

但我发现它对我的使用来说很麻烦而且过分。

有没有什么方法可以干净利落地实现“闭包风格”?

谢谢。

【问题讨论】:

  • 好吧...如果您想要一个类似闭包的功能,那么...为什么不使用闭包呢? :) 通过让发布者的生活复杂化,您试图实现的目标是什么?

标签: swift closures publish-subscribe combine backpressure


【解决方案1】:

听起来像是https://developer.apple.com/documentation/combine/publishers/prefixwhile/prefix(_:) 的工作

let numbers = (0...10)
cancellable = numbers.publisher
    .prefix(2)
    .sink { print("\($0)", terminator: " ") }

【讨论】:

  • 太棒了!似乎完全符合我的需要。
猜你喜欢
  • 2010-09-26
  • 2019-09-22
  • 2020-03-15
  • 1970-01-01
  • 2019-11-03
  • 2019-11-09
  • 2018-05-22
  • 1970-01-01
  • 2018-06-11
相关资源
最近更新 更多