A UIControl.Event publisher example

@Jon_Shier can you provide a bit of sample code for the TimerPublisher case not cancelling? I can take a look.

Let me try to clear up some of the Cancellable part.

Publisher is almost always a struct. When you subscribe something to it, the Publisher will create a Subscription (almost always a class) and send it to the Subscriber. This is a ref type because it's stateful - what's the pending demand, what have I sent, etc.

Since the Publisher created a reference out of thin air, something needs to retain it. Since the Subscription is sent to the Subscriber, it makes sense for the Subscriber to be responsible for it. Therefore, a Subscriber will maintain a reference to its upstream like this:

var upstream: Subscription?

Operators, being in the middle, need to also maintain a reference to their downstream, because they are sending them values:

let downstream: Downstream

(a property of the Subscription that the operator sends to its own Subscriber, of course)

It is not a weak reference for performance reasons. Sending values downstream is the "fast path" we optimize for. Having to always look up a weak reference is very expensive. So -- we have two retains: one up, one down. We need to break a cycle at some point. upstream can be set to nil upon cancel, but when to call it? Completion is one obvious point, but what about indefinite publishers like NotificationCenter? Should it be always required to call cancel or can we do it automatically?

At the termination of a stream, a Subscriber is holding on to its upstream strongly, keeping the subscriptions alive. If the stream does not finish, then just throwing away the last reference results in a leak.

To fix this, we could have weak references at every step -- but it is expensive, as I mentioned. We only need one point to break the cycle. We chose AnyCancellable as that point. It holds onto the Cancellable, but when it itself is deallocated, it calls cancel, resulting in each step along the chain throwing away any associated memory and allowing proper teardown to happen.

Hope this helps.

15 Likes