Reputation: 2402
I have the following task to do:
I have a segmented control
with two main tabs, the first tab has to load ads and data from the network, each of them is via different urls. What I want to do is query the ads and the data in parallel, after both of them have finished, I want to merge them into a single list and display it to the user. This can be done with a DispatchGroup
easily using .enter()
and .leave()
. However since this is in a segmented control
with a search bar
. The DispatchGroup
needs to be cancellable in order for a new set of ads and data to be loaded. Is there a way to cancel the DispatchGroup
, or is there a way to achieve this logic via other multithreading functionality?
Upvotes: 2
Views: 164
Reputation: 16327
This is exactly the kind of thing that Combine is good for (if you are using iOS 13). ie you can make your network requests a function of the currently selected segment and what is typed in search bar and when you call switchToLatest
it will cancel any uncompleted requests and only leave the most request that reflects the most recent state alive. I just wrote and example that does exactly that here:
https://github.com/joshuajhomann/Combine-NasaMediaSearch
Or more succinctly, setup two passthrough subjects, one for your search bar and one for your segmented control, combine them into a network request, flatten it with `switchToLatest, then assign the result wherever you need it:
private var data: [MyData] = []
private var searchTermSubject = PassthroughSubject<String, Never>()
private var segmentSubject = PassthroughSubject<SegmentType, Never>()
...
let searchResults = Publishers
.CombineLatest(
searchTermSubject,
segmentSubject
)
.debounce(for: .milliseconds(250), scheduler: RunLoop.main)
.map { combined -> AnyPublisher<[MyData],Never> in
let (term, segmentType) = combined
guard !(term.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty) else {
return Just(.empty).eraseToAnyPublisher()
}
return NetworkRequestPublisher
.search(query: term, mediaType: segmentType)
.replaceErrorWith([])
.eraseToAnyPublisher()
}
.switchToLatest()
.receive(on: RunLoop.main)
// assign or sink here depending on what you want to do
If you are not using iOS 13 then you can use OperationQueue or simply call cancel on the data task yourself.
Upvotes: 1