I currently have code like...
var isFetching = false
func fetch() {
guard !isFetching else { return }
fetching = true
apiPublisher
.receive(on: .main)
.handleEvents(receiveCompletion: { [weak self] _ in
self?.fetching = false
})
.assign(to: \.foo, on: self)
.store(in: &cancellables)
}
But I'm not happy with the way I'm stopping multiple requests happening like this. It works but feels clunky.
I feel like there should be a more "Combine-y" way of doing this.
Is there a more elegant/Combine-y way of doing this?
CodePudding user response:
The issue here is the fact that you have the entire Publisher subscription chain in a function (fetch()
) that can be called by virtually any other code at virtually any time from any thread. In order to do this in a "more Combine-y" you need to limit that. So the question is what calls this fetch()
function? If you wrap all those call sites in a Publisher and then setup a trigger.flatMap { apiPublisher }
and set up the flatMap
to ignore events while it's waiting for the current network request to complete.
Something like this:
trigger
.flatMap(maxPublishers: .max(1)) {
apiPublisher
}
.receive(on: .main)
.assign(to: \.foo, on: self)
.store(in: &cancellables)
The important thing to note here is that you only execute this code once (probably in the viewDidLoad if this is a view controller. Then when you want to make the request, you send an event through the trigger
Publisher. The flatMap
will ensure that only one apiPublisher subscription will happen at a time.