Multithreading With DispatchQueue – Modes Explanation

How to from one error create two errors? Add multithreading…

Multithreading is very powerful and mandatory to write user-friendly apps. It won’t be possible to download an image from the Internet or synchronize data with the server without freezing the user interface.

You can do it using DispatchQueue. This class allows switching between background threads and main.

There are 5 main background modes:

Each of these modes has different execution times and priorities.

Background – the lowest priority, it cares about battery consuming and tries to be executed at the best time for battery. It is for the long-running tasks and can last for even a few minutes, such as cleaning databases or import/export big old files.

Utility – low priority, it is for the long-running tasks that the user knows about it but doesn’t need the result, for example, creating data backup. It also cares about battery consuming.

Default – its priority is between Utility and UserInitiated. If you won’t use explicitly any then this type will be used.

UserInitiated – high priority, it needs to be done very fast but it can take a few seconds to finish, for example, the user clicks the Refresh button in News App. The user knows that the result won’t be instant but expects it quickly.

UserInteractive – the highest priority, it doesn’t care about battery consuming. It needs to be done very fast, for example, the user is swiping a view and you need to make some operation without blocking UI.

Let’s see different in code.

To demonstrate the difference between priorities, we’ll create five for loops with sleep inside and print the time when they execute.

First, create a utility extension to Date to print time in milliseconds.

extension Date {
var currentTimeInMs: Int64 {
Int64(self.timeIntervalSince1970 * 1000)

Now, create five loops. The order of these loops isn’t random, they are created from lowest to highest priority.

print(“Background queue start time: \(Date().currentTimeInMs)) .background).async {
for i in 1…3 {
print(“Background queue counter: \(i), time \(Date().currentTimeInMs))

print(“Utility queue start time: \(Date().currentTimeInMs)) .utility).async {
for i in 1…3 {
print(“Utility queue counter: \(i), time \(Date().currentTimeInMs))

print(“Default queue start time: \(Date().currentTimeInMs)) .default).async {
for i in 1…3 {
print(“Default queue counter: \(i), time \(Date().currentTimeInMs))

print(“UserInitiated queue start time: \(Date().currentTimeInMs)) .userInitiated).async {
for i in 1…3 {
print(“UserInitiated queue counter: \(i), time \(Date().currentTimeInMs))

print(“UserInteractive queue start time: \(Date().currentTimeInMs)) .userInteractive).async {
for i in 1…3 {
print(“UserInteractive queue counter: \(i), time \(Date().currentTimeInMs))

The first output shows 5 times when each task is scheduled, it should be very close to each other.

Background queue start time: 1573409560112
Utility queue start time: 1573409560112
Default queue start time: 1573409560113
UserInitiated queue start time: 1573409560113
UserInteractive queue start time: 1573409560113

Then, each second there will be five printed lines, let’s look closer to the first five.

UserInteractive queue counter: 1, time 1573409561114
UserInitiated queue counter: 1, time 1573409561114
Default queue counter: 1, time 1573409561114
Utility queue counter: 1, time 1573409561180
Background queue counter: 1, time 1573409561212

Look at the differences between queues start, execution time and print order. Remeber about an around 1-second delay.

UserInteractive – 1 millisecond
UserInitiated – 1 millisecond
Default – 1 millisecond
Utility – 67 milliseconds
Background – 199 milliseconds

Now, you can choose consciously mode for DispatchQueue.