Dispatch a task to a queue, be careful!

What We usually do

In this post, I bring up a topic which relates to Multi-thread. If you are an experience guy in mobile development, you certainly know about Multi-Thread, the Main-Thread and Background Thread, Dispatch Queue, and concepts.

I’m pretty sure that all of us have known that UI manipulation has to be done on Main-Thread. I/O tasks, Networking tasks, Service requests, etc should be done on Background. This is true but be careful.


I’m giving an example in practice,

People usually do this when they want to send a task to the main thread, they just do something like this

DispatchQueue.main.async {
//Update UI or do something.

We abuse this very often on a daily basis without unaware of the risk. I also have caught this from most of iOS developers, even seniors who I have known

If it’s on a background thread, then it’s okay to do. However when it’s been on the main thread already, then we break the sequential execution and add up some potential risks to our program


Let take a look at the below piece of code

print("Task 1")
print("Task 2")
print("Task 3")
//What is the output?

The code will be executed like this

Execution Order

The expected output will be

Task 1
Task 2
Task 3

How about this piece of code

print("Task 1")
DispatchQueue.main {
print("Task 2")
print("Task 3")
//What is the output?

Now, visualize the sequence

Execution Order Changed

The output will be

Task 1
Task 3
Task 2

The sequence is disordered, but it looks still acceptable, right?

Ok, try something more complex

print("Task 1 Done")
DispatchQueue.main.async { print("Task 2 Done") }
print("Task 3 Done")
DispatchQueue.main.async { print("Task 4 Done") }
print("Task 5 Done")
DispatchQueue.main.async { print("Task 6 Done") }
print("Task 7 Done")

The output will be

Task 1 Done
Task 3 Done
Task 5 Done
Task 7 Done
Task 2 Done
Task 4 Done
Task 6 Done

In practice, I have caught a stack trace which dispatched tasks to the main queue 5 times. Imagine the sequence, It is chaos.

Dispatch queue, dispatch queue,… everywhere, every time… is not a good way to implement a reliable project, I believe.

Where to go from here

When working in a complex project with a massive amount of code, We’re easily lose the track and forget about the risks until the final app comes out the end customers with crash, complaints, and unpredictable app behaviors.

So just simply remember one thing

If the execution is on the expected thread, don’t re-dispatch the task.

I give you an implementation sample which handles for dispatch main-queue

func dispatchAsyncOnMainQueueIfNeeded(_ block: ()-> Void) {
if Thread.isMainThread {
//Invoke block if already on Main-Thread, This remains the sequence of execution
} else {
//It's on background, dispatch the block to main queue.

Here we go. This is a basic handling for dispatch main-queue but shows you the principle, and how to handle the situation. You can apply this to anything not only the main-queue.

Hope this helps.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s