1

I need to execute synchronous requests on API using Swift. Requests must be queued. Meaning, if one is already in progress and it awaits response it must not be canceled or interrupted by the next synchronous request that enters queue or is already in queue.

Requests must be executed in order as they enter queue (FIFO). Next request must not start until previous is finished/completed in the queue.

Also, every single request in queue must be executed until queue is empty. Synchronous requests can enter queue at any time.

I meant to implement a Synchronous API Client as a singleton which contains its own Queue for queued requests. Requests must not stop/freeze UI. UI has to be responsive on user interaction all the time.

I know it can be done with semaphores but, unless you know what your are doing and you are completely sure how semaphores work, it is not the safest or maybe the best way do it. Otherwise, potential bugs and crashes could appear.

I'm expecting successful execution of every synchronous request that enters queue (by FIFO order, regardless if it returns success or an error as a response) and UI updates immediately after.

So, my question is what is the best way to approach and solve this problem? Thanks for your help and time.

Community
  • 1
  • 1
MattCodes
  • 489
  • 8
  • 21
  • You can wrap them in asynchronous `Operation` subclass, e.g. https://stackoverflow.com/a/27022598/1271826. – Rob Sep 06 '19 at 14:57

1 Answers1

2

You can create your own DispatchQueue and put you operations on it as DispatchWorkItems. It is serial per default. Just remember to call your completions on DispatchQueue.main if you plan to update the UI.

John Sundell has a wonderful article about DispatchQueues here:

https://www.swiftbysundell.com/articles/a-deep-dive-into-grand-central-dispatch-in-swift/

Jakob Mygind
  • 134
  • 4
  • I believe the OP understands all of this. The problem here is that if the task being dispatched is, itself, asynchronous, the serial queue will not wait for that. Hence the OP’s reference to semaphores (which make that network request behave in a synchronous manner). That article you reference also contemplates that, but the OP is right that semaphores are not a great solution, which is why we reach for other solutions, like asynchronous `Operation` subclasses, promises, Combine, etc. – Rob Sep 06 '19 at 18:02
  • @Jakob Mygind - thanks for the John Sundell article. It's very helpful. I believe I could also solve this problem using `DispatchGroup ` as shown in the article under the section: `Grouping and chaining tasks with DispatchGroup`. – MattCodes Sep 07 '19 at 14:08
  • @Rob - I agree, that is a great point that the problem here is that if the task being dispatched is, itself, asynchronous, the serial queue will not wait for that. The solution must execute requests one by one as they come and next request must not start until previous is finished/completed in the queue. – MattCodes Sep 07 '19 at 14:13
  • @MattCodes Right, dequeueing off your DispatchQueue on the DispatchGroup `notify` callback, and calling `enter()` on dequeue and `leave()`on completion should get the desired functionality, I'd say. – Jakob Mygind Sep 08 '19 at 12:14