'How to implement a simple event emitter style publisher in Combine?

So I'm getting started with Combine, and I want to have a component which publishes events like a simple event emitter.

So in other words, I want to have a model like this (pseudocode):

class MyModel {
   var onNewEvent: EventPublisher

   func foo(bar: Bar) {
       onNewEvent.publish(Event(bar))
   }
}

let model: MyModel...

model.onNewEvent.sink(
    receiveValue: { event in print(event) }
)

I can achieve something like this using a notification center publisher, but I want to avoid this unnecessary step if possible.

Is there such a thing as a simple publisher which just publishes values on command, or else what would be the idiomatic way to handle this in combine?



Solution 1:[1]

you can use a private(outside world cannot change/emit values) subject inside your model. and then expose it using a lazy publisher to let the outside world to subscribe.

class MyModel {
    private var myPassthroughSubject = PassthroughSubject<Bar, Never>() // make this subject `private`, so only inside methods can send values.
    lazy var myPublisher = myPassthroughSubject.eraseToAnyPublisher() // expose this publisher to the outside world.
    
    func foo(bar: Bar) {
        myPassthroughSubject.send(bar)
    }
}

struct Bar {
    
}

let model = MyModel()

model.myPublisher.sink(
    receiveValue: { event in print(event) }
)

model.foo(bar: .init())
model.foo(bar: .init())

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1