The Publisher receives the Subscriber
Publisher.receive(subscriber:)
The Publisher creates the Subscription passing in self
(the Publisher) and the Subscriber
let subscription = Subscription(self, subscriber)
Note: The Subscription retains a strong reference to the Publisher and a weak reference to the Subscriber
- The Subscription is "owned" by the Subscriber, so we keep a weak reference to avoid a retain cycle.
- Each side has a method of ending the Subscription.
- The Subscription adopts Cancellable, which allows the Subscriber to cancel the Subscription directly.
- The Subscriber can call
subscription.cancel()
directly- Most often the Subscription is wrapped in an
AnyCancellable
, which will automatically call.cancel()
when it is de-initialized.
- If the Subscriber is the only object holding a reference to the AnyCancellable, which is most often the case... then the Subscription will be canceled when the Subscriber is de-initialized, tying the lifetime of the Subscriber and the Subscription together.
- The Publisher can cancel the Subscription by sending a
.completion
event to the Subscriber.
The Subscriber receives the Subscription
subscriber.receive(subscription)
and requests a demand
for some number of values (often the demand is .unlimited
)
subscription.request(.unlimited)
Note: The Subscriber is only allowed to call
subscription.request(_ demand:)
a single time. This may seem surprising, but I think it makes sense if you understand the next part.
The Subscription receives the requested .demand
.
- The Subscription starts the Publisher producing some value(s)
- Hopefully producing asynchronously, since that's kind of the point, but it's not strictly necessary...
The Publisher produces a new value which is sent to the Subscriber.
let newDemand = subscriber.receive(state)
The Subscriber receives the published value and returns an additional .demand
to the Subscription.
- optionally, of course.
Note: This is the mechanism for requesting additional values and managing back-pressure from the Subscriber.
- As I understand it, calling
.request
on a Subscription more than once is a violation of the contract, and should be considered a programming error.- Which I think makes sense
Consider a Subscription as a one-way iterator for the Publisher's contents.
- We can't re-use an iterator once it's been advanced to the end.
- Instead we have to create a new iterator from the Collection.
- Once a Subscription is started, when a demand request has been made, it's a one-way trip.
- We have to request a new Subscription from the Publisher if we want to go again. 🎡