Syncing multiple asynchronous tasks in Swift
You may face the situations where it is needed some asynchronous tasks to be done first and then you can jump to the next stage of your swift program. In this article we are looking at different solutions we can apply to run the tasks asynchronously and get notified or get the results at the end of the process.
As a common case, you may need to store the results of multiple network requests first and then display the proper data to the user.
Indeed if you have to request many network resources for performing a feature of your application, it may consume more energy of the device and you may think twice about, but it is out of this article’s interest.
Let’s say we have a sample network request function as follows:
And there are some network requests that we want to fulfill via the network:
In the above example,
baseUrl indicates our base endpoint URL and the
endpoints are different requests from the web server.
Multiple Independent Tasks (Concurrent Queue)
We can have different async tasks which are independent of each other. It means we can run them in any order and the result of one is not related to the other task.
Grand Central Dispatch or GCD automatically manages the thread creation and balances them based on available device resources in iOS.
We can create a bunch of asynchronous tasks with
DispatchGroup and continue our job when all of them is completed:
We have notified the main thread when tasks are done but it could be any other threads. The following output could be the result (or any arbitrary order of completion of sub-tasks):
Task albums is doneTask posts is doneTask todos is doneTask comments is doneTask users is doneTask photos is doneAll Tasks are done
As you can see, when all the tasks are processed we received the “All Tasks are done” message.
There is a pattern which is highly recommended to solve this issue: Promises.
Generally speaking, a promise represents the eventual result of an asynchronous task, respectively the error reason when the task fails. Similar concepts are also called futures (see this wiki article for more information Futures and promises).
We can suppose 3 different states of a promise:
Pending : unresolved task and the result is not yet available
Fulfilled : resolved task with some value (successful response)
Rejected : resolved task with error
There are a bunch of Cocoapods libraries to provide promises. One of the best implementations in Swift is Google Promises:
Promises is a modern framework that provides a synchronization construct for Swift and Objective-C. - google/promises
Now we can update the solution using Promises:
As can be seen, promises ease the async task process. In
performNetworkPromise we first created a pending process that some data will be returned. It is like an empty async request container that we have initialized. The type
Data in the promise determines what type of data it would be fulfilled with. Then we performed the network request. As a result, when we have a response we fill the promise with the data from that response.
We created an array of network requests in
networkPromises . The
all class method waits for all the provided promises , here the network requests, to be fulfilled. Once all of them have been fulfilled with proper data, it will an array of all fulfilled values,
The other promise implementation which is so popular in Swift community is PromiseKit.
Promises for Swift & ObjC. Contribute to mxcl/PromiseKit development by creating an account on GitHub.
They are so similar to each other (the keywords are almost the same). You can check it out yourself. Just keep in mind that you should not use both of them in a single scope.
You can find the source code of this article at below repository: