Combine
01 / 02

Combine: Subjects, Combining Streams & Retain Cycles

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 5

Combining 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 flags

Avoiding 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 closure

Type-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