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.
2
Answers
The
sink
method returns a singleAnyCancellable
that you can store ina 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 callscancel()
when deinitialized."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.