Swift Combine makeConnectable with PassthroughSubject

Viewed 1316

I'm having a hard time using the Connectable protocol on a PassthroughSubject. What I would like to do is be able to control when the PassthroughSubject begins sending events to its subscribers.

let eventPublisher = PassthroughSubject<String, Never>().makeConnectable()
let subscriber = MySubscriber()
eventPublisher.subscribe(subscriber)

eventPublisher.send("Hello") // Does not compile, send not found in Publisher.MakeConnectable

let cancelable = eventPublisher.connect()
// expect MySubscriber to recieve "Hello"

I'm new to Combine, but I don't understand how I can send values downstream to subscribers after becoming a connectable publisher and calling connect(). The docs are quite sparse on this topic and I'm hoping someone can show me how to achive this behavior.

2 Answers

You're close, but misunderstanding what the makeConnectable enables. It doesn't "queue up" data and prepare it for sending when it's available, it controls when the subscription is established.

As soon as the subscription is allowed (with .connect()), the publisher "is live" and a subscriber would receive a value that you send. However, anything you send before connect() is invoked is essentially dropped, not queued.

That said, if you invoke eventPublisher.send('after connect') after the last line, that will be received by the subscriber.

It sounds like what you want is a CurrentValueSubject, not a PassthroughSubject.

let countPublisher = CurrentValueSubject<Int,Never>(0)

var storage = Set<AnyCancellable>()

func f() {
    self.countPublisher.value = 1
    self.countPublisher
        .sink {print($0)} // 1
        .store(in:&self.storage)
}

As you can see, we can prime the pump with a stored value before any subscriber comes along, and when a subscriber does come along, it immediately receives the stored value. And after that, we can say .send and the subscriber(s) will receive whatever we send.

Related