Swift Threading: When to use DispatchQueue.main.async?

I just ran into the exact situation discribed in your Question: viewDidLoad() calling DispatchQueue.main.async.

In my case I was wanting to modify Storyboard defaults prior to displaying a view.

But when I ran the app, the default Storyboard items were momentarily displayed. The animated segue would finish. And only THEN would the UI components be modified via the code in viewDidLoad(). So there was this annoying flash of all of the default storyboard values before the real values were edited in.

This was because I was modifying those controls via a helper function that always first dispatched to the main thread. That dispatch was too late to modify the controls prior to their first display.

So: modify Storyboard UI in viewDidLoad() without dispatching to the Main Thread. If you're already on the main thread, do the work there. Otherwise your eventual async dispatch may be too late.


The primary use of DispatchQueue.main.async is when you have code running on a background queue and you need a specific block of code to be executed on the main queue.

In your code, viewDidLoad is already running on the main queue so there is little reason to use DispatchQueue.main.async.

But isn't necessarily wrong to use it. But it does change the order of execution.

Example without:

class MyViewController: UIViewController {
    func updateUI() {
        print("update")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        print("before")
        updateUI()
        print("after")
    }
}

As one might expect, the output will be:

before
update
after

Now add DispatchQueue.main.async:

class MyViewController: UIViewController {
    func updateUI() {
        print("update")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        print("before")
        DispatchQueue.main.async {
            updateUI()
        }
        print("after")
    }
}

And the output changes:

before
after
update

This is because the async closure is queued up to run after the current runloop completes.