Combine: Subjects, Combining Streams & Retain Cycles
PassthroughSubject vs. CurrentValueSubject
let events = PassthroughSubject<String, Never>()
events.send("tapped") // no memory of past values
let state = CurrentValueSubject<Int, Never>(0)
state.value // readable directly
state.send(5) // new subscribers immediately get 5Combining Multiple Streams
Publishers.CombineLatest(userPublisher, settingsPublisher)
.sink { user, settings in
// fires whenever EITHER stream emits a new value
}
.store(in: &cancellables)
// Declaratively coordinates two async sources, instead of
// manually tracking two completion flagsAvoiding Retain Cycles
publisher.sink { [weak self] value in
self?.handle(value)
}.store(in: &cancellables)
// self strongly holding the cancellable, while the closure
// strongly captures self, can create a retain cycle --
// [weak self] breaks it, same as with any Swift closureType-Safe Errors
Combine's Publisher<Output, Failure> generic signature statically declares what error type a stream can terminate with -- mismatched types between a Publisher and a downstream operator are caught by the compiler, not discovered as a runtime crash.
Combine vs. async/await
async/await excels at expressing a single asynchronous operation's result. Combine's strength is modeling ongoing streams of multiple values over time -- repeated UI events, continuously-changing @Published state -- a genuinely different use case the two complement rather than fully replace.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free