According to the swift combine documentation, the proper way to connect a subscriber to a publisher is with the publishers subscribe<S>(S)
protocol extension method. Then the publisher creates a subscription and passes that subscription on to the subscriber. All's well and good so far.
What I can't seem to figure out is how to gain access to that subscription and retain it in the calling code. How is sink()
implemented such that it can return that subscription? Unless I'm mistaken, the subscription is responsible for retaining its subscriber, which means I can't store a reference to the subscription in the subscriber. And since Subscription isn't class bound, it can't be weak.
CodePudding user response:
The cancellable retains the subscription (or possibly is the subscription. Remember Subscriptions are Cancellables.) So when you retain the Cancellable, you are retaining the subscription.
CodePudding user response:
Here's an example of how sink
might be implemented
import Combine
import Foundation
extension Publisher {
func mockSink(
receiveValue: @escaping (Output) -> Void,
receiveCompletion: @escaping (Subscribers.Completion<Failure>) -> Void) -> AnyCancellable {
var result : AnyCancellable!
let anySubscriber = AnySubscriber(
receiveSubscription: { subscription in
subscription.request(.unlimited)
result = AnyCancellable({subscription.cancel()})
},
receiveValue: { (value : Output) in receiveValue(value); return .unlimited},
receiveCompletion: receiveCompletion)
subscribe(anySubscriber)
return result
}
}
var subscriptions = Set<AnyCancellable>()
["one", "two", "three"].publisher
.mockSink(receiveValue: {debugPrint($0)}, receiveCompletion: {debugPrint($0)})
.store(in: &subscriptions)
As you can see the ability to return an AnyCancellable
arises from the magic of AnySubscriber
which returns its subscription in a closure. AnySubscriber
is a handy tool to have when implementing custom Publishers
and it may be helpful if you want to implement your own Subscriber
type. But basically a Subscriber
only exposes the subscription if it is designed to.