Home > OS >  Swift Combine Cancel Publishers Without AnyCancellable
Swift Combine Cancel Publishers Without AnyCancellable

Time:01-20

I have my networking library based on Combine. Anywhere in my app I can make a request and the networking library returns a publisher, it doesn't have access to the AnyCancellable that is created that actually triggers the pipeline. What I need is the ability to cancel all network requests when the use logs out. Is there a way to cancel Combine pipelines from the publisher not the AnyCancellable.

Here is an example:

    var subscribers = [AnyCancellable]()
    let url = URL(string:"https://www.apeth.com/pep/manny.jpg")!
    let request: AnyPublisher<UIImage, URLError> = URLSession.shared.dataTaskPublisher(for: url)
        .compactMap { UIImage(data:$0.data) }
        .share()
        .eraseToAnyPublisher()
    
    request
        .sink(receiveCompletion: { _ in
            print("subscription2 completed")
        }, receiveValue: { image in
            print("subscription1 value: \(image.scale)")
        })
        .store(in: &subscribers)
    
    // request.cancel()

I would like to call something like request.cancel() on the publisher so that the receiveValue is never triggered.

CodePudding user response:

What I need is the ability to cancel all network requests when the use logs out.

I suggest you setup a publisher that emits when the user logs out. Then in your API system, you can use prefix(untilOutputFrom: logoutPublisher).

That way, all your network requests will cancel when the logoutPublisher emits.

CodePudding user response:

The sink method returns a single AnyCancellable that you can store in a dedicated property for the request instead of storing the cancellable in the array.

When you need to cancel the subscription, just deinitialize the cancellable, because, according to the documentation "An AnyCancellable instance automatically calls cancel() when deinitialized."

private var requestCancellable: AnyCancellable?

func setUpSubscription() {
    requestCancellable = request
        .sink(receiveCompletion: { _ in
            print("subscription2 completed")
        }, receiveValue: { image in
            print("subscription1 value: \(image.scale)")
        })
}

func cancelSubscription() {
    requestCancellable = nil
}
  • Related