You said:
I know when we use .async to execute the task we won't block the main thread.
Yes, we often dispatch asynchronously to a background queue to avoid blocking the main thread. But, more accurately, we technically use async to avoid blocking the current thread. Sure, if you’re on the main thread, that means we’re not blocking the main thread. But if you’re currently running on a background thread, then async just keeps you from blocking that current background thread.
... but why we use DispatchQueue.main.async?
This is commonly used when you’re already on a background thread, but have something (like a UI update) that must be run on the main thread. Then you’d dispatch that UI update from the background thread back to the main queue. And we’d generally do this asynchronously because there’s no point in having that background thread wait for the UI update.
E.g.
DispatchQueue.global().async {
// do something computationally intensive here ...
// ... but when you want to update the UI with the result, you’d dispatch that back to the main queue
DispatchQueue.main.async {
self.label.text = ...
}
}
Or you’d use the same pattern when using URLSession (or anything that runs on a background thread). We’d use DispatchQueue.main.async if we’re currently on some background thread, but need to perform UI updates, which must always happen on the main thread. So we’d dispatch those UI updates back to the main queue.
That’s why we use DispatchQueue.main.async. That having been said, while there is rarely any utility to it, you technically can dispatch asynchronously from the main thread back to itself, like you have in your question. All that will happen is that the dispatched code will be added to the end of the main queue, but won’t run until you finish whatever you were previously doing on the main thread.
For example, imagine that the following is run on the main thread
print("a")
DispatchQueue.main.async {
print("b")
}
print("c")
You’ll see “a”, the print("b") will be queued (but not run yet), you’ll then carry on the main thread and will see “c”. Then when you eventually yield back to the app’s run loop, only then will the main thread be freed so that print("b") can be performed. So you’ll see “a” and “c”, first, and then “b”!