Home > Net >  Is there a Combine-y way to stop multiple requests being triggered?
Is there a Combine-y way to stop multiple requests being triggered?

Time:11-06

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.

  • Related