Combine: “Lazy” CurrentValueSubject

This is a technique suggested to me by Jordan Gustafson (@minnesota_gus) on how to make a CurrentValueSubject that doesn’t require an initial value. This should probably be developed into an actual type which conforms to Subject, but I haven’t figured that out yet.

import Foundation
import Combine
class Example {
private var index = 1
private let valuePublisher = CurrentValueSubject<Int?, Never>(nil)
var value: AnyPublisher<Int, Never> {
valuePublisher.compactMap({ $0 }).eraseToAnyPublisher()
}
func doSomething() {
print("[Example] sending value: \(index)")
valuePublisher.send(index)
index += 1
}
}
let example = Example()
print("First subscription.")
let subscription1 = example.value.sink { print("sub1: \($0)") }
example.doSomething()
print("Second subscription.")
let subscription2 = example.value.sink { print("sub2: \($0)") }
example.doSomething()

This will produce the following output:

First subscription.
[Example] sending value: 1
sub1: 1
Second subscription.
sub2: 1
[Example] sending value: 2
sub2: 2
sub1: 2

As you can see, the first subscription did not receive a value until the first time doSomething() was called. Conversely, the second subscription—which was added after the first value had been sent—received a value immediately. Both subscriptions receive all values thereafter.