Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does subscribe(subject) return AnyCancellable but subscribe(subscriber) Void?

Tags:

swift

combine

I'm working with Swift Combine and do not get the difference between

func subscribe<S>(_ subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input

and

func subscribe<S>(_ subject: S) -> AnyCancellable where S : Subject, Self.Failure == S.Failure, Self.Output == S.Output

Why does one return an AnyCancellable wheras the other Void?

I have a custom Subscriber so is it totally safe for me to use

myPublisher.subscribe(myCustomSubscriber)

without having to deal with an AnyCancellable?

like image 330
swalkner Avatar asked Dec 10 '25 03:12

swalkner


1 Answers

Update:

As my explanation below, your custom Subscriber (I named it MySubscriber in the code below) should implement Cancellable protocol. Now you can manage the subscription by adding it to a Set<AnyCancellable>. When subscriber is cancelled, the subscription is canceled as well.


I have the same concern. I have a custom subscriber Subscribers.MySubscriber and want to add function Publisher.mySubscriber() like Combine did with Subscribers.Sink and Publisher.sink(). But I don't know how Publisher.sink() can return a AnyCancellable. After a few minutes, I guess a solution how Publisher.sink() is implemented:

extension Publisher {
    public func mySink(receiveCompletion: @escaping ((Subscribers.Completion<Self.Failure>) -> Void), receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable {
        let sink = Subscribers.Sink<Self.Output, Self.Failure>(receiveCompletion: receiveCompletion, receiveValue: receiveValue)
        subscribe(sink)
        return AnyCancellable(sink)
    }
}

So a customized subscriber should conform to Cancellable, and keep subscription reference, to cancel the subscription when subsriber's cancel() called, like below:

final class MySubscriber<Input, Failure: Error>: Subscriber, Cancellable {

    var subscription: Subscription?
    
    // ...
    
    init() {}

    func receive(subscription: Subscription) {
        // ...
        self.subscription = subscription
    }

    func receive(_ input: Input) -> Subscribers.Demand {
        // ...
        return .unlimited
    }

    func receive(completion: Subscribers.Completion<Failure>) {
        // ...
    }

    func cancel() {
        subscription?.cancel()
        subscription = nil
    }
}

So my function Publisher.mySubscriber() function will be:

extension Publisher {
    public func mySubscriber() -> AnyCancellable {
        let mySubscriber = MySubscriber<Output, Failure>()
        subscribe(mySubscriber)
        return AnyCancellable(mySubscriber)
    }
}
like image 97
huync Avatar answered Dec 13 '25 00:12

huync



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!